﻿using CodeSmith.Data.Linq;
using ezCloud.Api.Common;
using ezCloud.Api.Models;
using ezCloud.Data;
using Microsoft.AspNet.Identity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Linq;
using System.Data.SqlTypes;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Script.Serialization;

namespace ezCloud.Api.Controllers
{
    [ApiAuthorize]
    [RoutePrefix("api/Room")]
    public class RoomController : ApiController
    {
        private Common.MemoryCacher memCache = new Common.MemoryCacher();

        public RoomController()
        {
        }

        private class extraTravellers : Travellers
        {
            private bool _isChild;

            public bool IsChild
            {
                get
                {
                    return _isChild;
                }

                set
                {
                    _isChild = value;
                }
            }

            public extraTravellers(Travellers t, bool isChild) : base()
            {
                foreach (PropertyInfo propertyInfo in typeof(Travellers).GetProperties())
                {
                    if (propertyInfo.CanRead && propertyInfo.CanWrite)
                    {
                        try
                        {
                            propertyInfo.SetValue(this, propertyInfo.GetValue(t));
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(propertyInfo.Name);
                        }
                    }
                    this.IsChild = isChild;
                }
            }
        }

        private class TravellerList
        {
            private EntitySet<extraTravellers> _list;

            public EntitySet<extraTravellers> List
            {
                get
                {
                    return _list;
                }

                set
                {
                    _list = value;
                }
            }

            public TravellerList(EntitySet<Travellers> tl)
            {
                _list = new EntitySet<extraTravellers>();
                foreach (var t in tl)
                {
                    var tt = new extraTravellers(t, false);
                    _list.Add(tt);
                }
            }
        }

        public class DashboardApp
        {
            // Thông kê hôm nay
            public int todayStats_roomOccupied { get; set; }

            public int todayStats_roomDueOut { get; set; }
            public int todayStats_roomTodayStayOver { get; set; }
            public int todayStats_roomArrival { get; set; }
            public int todayStats_roomTotalRoomsToSell { get; set; }

            public int todayStats_Projected_roomOccupied { get; set; } //{{todayStats.roomOccupied+todayStats.roomArrival}}

            public double todayStats_Projected_Occupancy { get; set; } //{{ ( (todayStats.roomOccupied+todayStats.roomArrival-todayStats.roomDueOut+todayActivity.Day_Use)*100/todayStats.roomTotalRoomsToSell).toFixed(2); }}

            // Hoạt động trong ngày

            public int todayActivity_Arrived { get; set; }

            public int todayActivity_Due_To_Arrive { get; set; }
            public int todayActivity_Checked_Out { get; set; }
            public int todayActivity_Due_Out { get; set; }
            public int todayActivity_Day_Use { get; set; }

            // Tong khach dang o
            public int hotelGuests_Expected_In_House_Children { get; set; }

            public int hotelGuests_Expected_In_House_Adult { get; set; }

            public decimal Total_Revenue { get; set; }
            public decimal Total_Payment { get; set; }
        }
        public class MainTravellers
        {
            public string Fullname { get; set; }
            public int TravellerId { get; set; }
        }
        public class BookingList
        {
            public BookingList()
            {

            }
            public string BookingStatus { get; set; }
            public int Adults { get; set; }

            public DateTime? ArrivalDate { get; set; }
            public int Child { get; set; }
            public DateTime? DepartureDate { get; set; }
            public Reservations Reservations  { get; set; }
            public MainTravellers Travellers { get; set; }
            public int? RoomId { get; set; }
            public int ReservationRoomId { get; set; }

            public EntitySet<Travellers> TravellersList { get; set; }
            public bool Foc { get; set; }
            public double DiscountPercentage { get; set; }
            public decimal DiscountFlat { get; set; }
            public int? RoomPriceId { get; set; }
        }


        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomStatus")]
        public async Task<IHttpActionResult> getAllRoomStatus(DateTime date)
        {
            
            var currentTime = DateTime.Now;
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            

            var lastCache = memCache.GetValue("STATUS_" + user.HotelId);
            if (lastCache != null)
            {
                return Ok(lastCache);
            }

           

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            if (currentHotel == null) return Ok();

            //Extra service
            var cacheExtraService = memCache.GetValue("EXTRASERVICES_" + user.HotelId);
            object ExtraService;
            if (cacheExtraService != null)
            {
                ExtraService = cacheExtraService;
            }
            else {
                var es = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId);
                var escats = context.ExtraServiceCategories.Where(r => r.HotelId == user.HotelId && !r.IsHidden);
                var esitems = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && r.IsHidden == false && escats.Contains(r.ExtraServiceCategories));
                ExtraService = new
                {
                    ExtraServiceTypes = es,
                    ExtraServiceCategories = escats,
                    ExtraServiceItems = esitems
                };
                memCache.AddByHotelId(user.HotelId, "EXTRASERVICES_" + user.HotelId, ExtraService, DateTimeOffset.UtcNow.AddHours(1));
            }

            date = date.AddMinutes(-currentHotel.TimeZoneOffset);

            DataTable AvailableRooms = new DataTable();
            AvailableRooms = Utilities.GetAvailableRooms(date, date);

            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false && room.RoomTypes.IsHidden == false && room.IsDeleted == false).
                Select(rm => new
                {
                    Room = rm,
                    RoomType = rm.RoomTypes,
                    RoomRepairList = rm.RoomRepairList.Where(rpl => rpl.IsDeleted == false).ToList()
                }).ToList();
            
            //Dictionary<int, object> roomBookingList = new Dictionary<int, object>();
            //Dictionary<int, object> roomBookingList1 = new Dictionary<int, object>();

            var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId !=null && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new
                    {
                        r.BookingStatus,
                        r.Adults,
                        r.ArrivalDate,
                        r.Child,
                        r.DepartureDate,
                        r.Reservations,
                        Travellers = new
                        {
                            r.Travellers.Fullname,
                            r.Travellers.TravellerId
                        },
                        r.RoomId,
                        r.ReservationRoomId,
                        r.TravellersList,
                        r.Foc,
                        r.DiscountPercentage,
                        r.DiscountFlat,
                        r.RoomPriceId,
                    }).ToList();
            /*foreach (var room in roomList)
            {
                var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == room.Room.RoomId && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new
                    {
                        r.BookingStatus,
                        r.Adults,
                        r.ArrivalDate,
                        r.Child,
                        r.DepartureDate,
                        r.Reservations,
                        Travellers = new
                        {
                            r.Travellers.Fullname,
                            r.Travellers.TravellerId
                        },
                        r.RoomId,
                        r.ReservationRoomId,
                        r.TravellersList,
                        r.Foc,
                        r.DiscountPercentage,
                        r.DiscountFlat,
                        r.RoomPriceId,
                    }).ToList();

                roomBookingList[room.Room.RoomId] = bookingList;
            }*/
            /*

            List<IQueryable<BookingList>> queries = new List<IQueryable<BookingList>>();

            foreach (var room in roomList)
            {
                var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == room.Room.RoomId && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new BookingList
                    {
                        BookingStatus = r.BookingStatus,
                        Adults = r.Adults,
                        ArrivalDate = r.ArrivalDate,
                        Child = r.Child,
                        DepartureDate = r.DepartureDate,
                        Reservations = r.Reservations,
                        Travellers = new MainTravellers
                        {
                            Fullname = r.Travellers.Fullname,
                            TravellerId = r.Travellers.TravellerId
                        },
                        RoomId = r.RoomId,
                        ReservationRoomId = r.ReservationRoomId,
                        TravellersList = r.TravellersList,
                        Foc = r.Foc,
                        DiscountPercentage = r.DiscountPercentage,
                        DiscountFlat = r.DiscountFlat,
                        RoomPriceId = r.RoomPriceId,
                    });
                queries.Add(bookingList);

                //roomBookingList[room.Room.RoomId] = bookingList;
            }
            var results = context.ExecuteQuery(queries);
            foreach (var room in roomList)
            {
                roomBookingList1[room.Room.RoomId] =  results.GetResult<BookingList>().ToList();
            }
            */
            
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId &&
                ((rr.ArrivalDate <= date.AddDays(1) && rr.DepartureDate >= date) ||
                (rr.ArrivalDate <= date && rr.BookingStatus == "CHECKIN")))
                .Select(rr => new
                {
                    rr.BookingStatus,
                    rr.Adults,
                    rr.IsGroupMaster,
                    rr.ArrivalDate,
                    rr.Child,
                    rr.DepartureDate,
                    rr.Reservations,
                    rr.TravellerId,
                    Travellers = new
                    {
                        rr.Travellers.Fullname,
                        rr.Travellers.TravellerId,
                        rr.Travellers.Countries.CountryName,
                        rr.Travellers.Countries.CountryCode
                    },
                    rr.RoomId,
                    rr.ReservationRoomId,
                    rr.TravellersList,
                    //rr.PaymentsList,
                    rr.Foc,
                    rr.DiscountPercentage,
                    rr.DiscountFlat,
                    rr.RoomPriceId,
                    //rr.RoomExtraServicesList,
                    //rr.RoomExtraServiceItemsList,
                    rr.Price,
                    rr.Note,
                    rr.Reservations.Company,
                    rr.Reservations.Source,
                    rr.Reservations.Market,
                    rr.Reservations.IsGroup,
                    //rr.RoomMoveList
                }).ToList();
            List<int> rrIdList = new List<int>();
           
            foreach (var rr in reservationRooms)
            {
                rrIdList.Add(rr.ReservationRoomId);
            }
            

            var allResExtra = context.ReservationTravellerExtraInformation.Where(etxi => etxi.HotelId == user.HotelId).Select(
                etxi => new { etxi.IsChild, etxi.ReservationTravellers.TravellerId, etxi.ReservationTravellers.ReservationRoomId }
                ).ToList();
            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();

            //group into batch query
            var allRelatedRoomExtraServicesQuery = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRelatedPaymentsQuery = context.Payments.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomMovesQuery = context.RoomMove.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomExtraServiceItemsQuery = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));

            var roomTypesQuery = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId && !roomType.IsHidden);
            var planListQuery = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId);
            var statusColorsQuery = context.StatusColors.Where(sc => sc.HotelId == user.HotelId);
            var paymentMethodsQuery = context.PaymentMethods;
            var remarkEventsQuery = context.RemarkEvents;
            var sourceListQuery = context.Source.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var companyListQuery = context.Company.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var marketListQuery = context.Market.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var floorListQuery = context.Floors.Where(f => f.HotelId == user.HotelId && ( f.IsActive == true || f.IsActive == null ) && f.IsDeleted == false);

            var results2 = context.ExecuteQuery(roomTypesQuery, planListQuery, statusColorsQuery, paymentMethodsQuery, 
                                                remarkEventsQuery, sourceListQuery, companyListQuery, marketListQuery,
                                                allRelatedRoomExtraServicesQuery,allRelatedPaymentsQuery, allRoomMovesQuery, allRoomExtraServiceItemsQuery, floorListQuery
                                                );

            
            var roomTypes = results2.GetResult<RoomTypes>().ToList();
            var planList = results2.GetResult<RoomPrices>().ToList();
            var statusColors = results2.GetResult<StatusColors>().ToList();
            var paymentMethods = results2.GetResult<PaymentMethods>().ToList();
            var remarkEvents = results2.GetResult<RemarkEvents>().ToList();
            var sourceList = results2.GetResult<Source>().ToList();
            var companyList = results2.GetResult<Company>().ToList();
            var marketList = results2.GetResult<Market>().ToList();
            var allRoomExtraServiceList = results2.GetResult<RoomExtraServices>().ToList();
            var allRelatedPayments = results2.GetResult<Payments>().ToList();
            var allRoomMoves = results2.GetResult<RoomMove>().ToList();
            var allRoomExtraServiceItemsList = results2.GetResult<RoomExtraServiceItems>().ToList();
            var floorList = results2.GetResult<Floors>().ToList();
            //Data correction methods

            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }
            if (paymentMethods.Count == 0)
            {
                //Auto generate payment methods
                var cash = new PaymentMethods();
                cash.PaymentMethodName = "CASH";
                cash.PaymentMethodDescription = "CASH_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(cash);
                var credit = new PaymentMethods();
                credit.PaymentMethodName = "CREDIT";
                credit.PaymentMethodDescription = "CREDIT_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(credit);
                var banktransfer = new PaymentMethods();
                banktransfer.PaymentMethodName = "BANK_TRANSFER";
                banktransfer.PaymentMethodDescription = "BANK_TRANSFER";
                context.PaymentMethods.InsertOnSubmit(banktransfer);
                var cityledger = new PaymentMethods();
                cityledger.PaymentMethodName = "CITY_LEDGER";
                cityledger.PaymentMethodDescription = "CITY_LEDGER";
                context.PaymentMethods.InsertOnSubmit(cityledger);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            if (remarkEvents.Count == 0)
            {
                RemarkEvents remarkEventCheckIn = new RemarkEvents();
                remarkEventCheckIn.RemarkEventCode = "CHECKIN";
                remarkEventCheckIn.RemarkEventName = "CHECK_IN";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckIn);
                RemarkEvents remarkEventCheckOut = new RemarkEvents();
                remarkEventCheckOut.RemarkEventCode = "CHECKOUT";
                remarkEventCheckOut.RemarkEventName = "CHECK_OUT";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckOut);
                RemarkEvents remarkEventReservation = new RemarkEvents();
                remarkEventReservation.RemarkEventCode = "RESERVATION";
                remarkEventReservation.RemarkEventName = "RESERVATION";
                context.RemarkEvents.InsertOnSubmit(remarkEventReservation);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }

            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }
            var endTime = DateTime.Now;
            var retval = new
            {

                reservationRooms = reservationRooms,
                rooms = roomList,
                //roomBookingList = roomBookingList,
                BookingList = bookingList,
                roomTypes = roomTypes,
                floorList = floorList,
                planList = planList,
                statusColors = statusColors,
                currencies = currencies,
                currenciesISO = currenciesISO,
                allResExtra = allResExtra,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },
                paymentMethods = paymentMethods,
                remarkEvents = remarkEvents,
                sourceList,
                companyList,
                marketList,
                executionTime = (endTime - currentTime).TotalMilliseconds,
                AvailableRooms = AvailableRooms,
                RelatedPayments = allRelatedPayments,
                RoomMoves = allRoomMoves,
                RoomExtraServicesList = allRoomExtraServiceList,
                RoomExtraServiceItemsList = allRoomExtraServiceItemsList,
                ExtraService= ExtraService,
            };
            memCache.Add("STATUS_" + user.HotelId, retval, DateTimeOffset.UtcNow.AddHours(1));

            return Ok(retval);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="from"></param>
        /// <returns></returns>
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DashboardForApp")]
        public async Task<IHttpActionResult> getDashboardForApp(DateTime from)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            //var memcache = new MemoryCacher();
            var cacheKey = "DASHBOARD_" + user.HotelId + "_" + string.Format("{0:yyyyMMdd}", from) + "_" + 0;
            var timelineCache = memCache.GetValue(cacheKey);
            if (timelineCache != null)
                return Ok(timelineCache);

            //var lastCache = memCache.GetValue(cacheKey);
            //if (lastCache != null)
            //{
            //    return Ok(lastCache);
            //}


            

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();

            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }

            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }

            var date = from.AddMinutes(-currentHotel.TimeZoneOffset);
            var datefrom = from.AddMinutes(-currentHotel.TimeZoneOffset);
            var dateto = datefrom.AddDays(1);

            DashboardApp statisDash = new DashboardApp();

            DataTable AvailableRooms = new DataTable();
            AvailableRooms = Utilities.GetAvailableRooms(datefrom, date);
            IEnumerable<DataRow> AvailableRoomsRow =
                   from order in AvailableRooms.AsEnumerable()
                   select order;

            var TotalRoomCount = (int)AvailableRoomsRow.FirstOrDefault()["AvailableRooms"];
            var TotalrepairRoomCount = (int)AvailableRoomsRow.FirstOrDefault()["RepairRooms"];

            //Get Payment
            decimal tmpTotalPayment = 0;
            tmpTotalPayment = Convert.ToDecimal(context.Payments.Where(pay => pay.HotelId == user.HotelId && pay.CreatedDate >= datefrom && pay.CreatedDate < dateto && pay.RefPaymentId == null && pay.PaymentTypeName != "DELETED").Sum(apay => apay.Amount));

            statisDash.Total_Payment = tmpTotalPayment;
            //get Revenue
            statisDash.Total_Revenue = Convert.ToDecimal(
                context.Payments.Where(p => p.HotelId == user.HotelId)
                .Join(context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.DepartureDate >= datefrom && rr.DepartureDate < dateto && rr.BookingStatus == "CHECKOUT"), p => p.ReservationRoomId, c => c.ReservationRoomId, (p, c) => new { Amount = p.Amount }).Sum(a => a.Amount)
                );

            // Lay so lieu thong ke

            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false).ToList();

            // Dem du lieu

            var listReservationRoom = context.ReservationRooms.Where(r => r.HotelId == user.HotelId).ToList();

            //var listReservationTravellers = context.ReservationTravellers.Where(rt => rt.ReservationTravellerExtraInformationList.Where(rtif => rtif.HotelId == user.HotelId && rtif.ReservationTravellerId == rt.ReservationTravellerId).Select(rt.ReservationRoomId,rtif.IsChild)).
            var listReservationTravellerExtraInformation = context.ReservationTravellerExtraInformation.Where(t => t.HotelId == user.HotelId)
               .Join(context.ReservationTravellers, rt => rt.ReservationTravellerId, rtei => rtei.ReservationTravellerId, (rt, rtei) => new { rt.ReservationTravellers.ReservationRoomId, rt.IsChild }).ToList();

            //Phòng khách đang ở
            statisDash.todayStats_roomOccupied = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Count();
            //Phòng sẽ đi trong ngày hôm nay
            statisDash.todayStats_roomDueOut = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Count();
            //Phòng đã checkin từ hôm trước đó, hôm nay vẫn ở và chưa đi
            statisDash.todayStats_roomTodayStayOver = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto).Count();
            //Phòng có trạng thái Booked, có ngày đến là ngày thống kê,  nhưng chưa đến
            statisDash.todayStats_roomArrival = listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Count();

            statisDash.todayStats_roomTotalRoomsToSell = TotalRoomCount;

            //Khách đang ở ngày hiện tại vẫn chưa đi + dự kiến đến
            statisDash.todayStats_Projected_roomOccupied = statisDash.todayStats_roomArrival + listReservationRoom.Where(r => r.ArrivalDate < datefrom && r.DepartureDate > dateto && (r.BookingStatus == "CHECKIN")).Count()
                                                + listReservationRoom.Where(r => r.ArrivalDate >= datefrom && r.ArrivalDate < dateto && r.DepartureDate >= datefrom && (r.BookingStatus == "CHECKIN")).Count();

            //Đếm số phòng đã đến trong ngày hiện tại và ngày đi lớn hơn ngày hiện tại
            statisDash.todayActivity_Arrived = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Count();
            //Đếm số phòng sẽ đến
            statisDash.todayActivity_Due_To_Arrive = statisDash.todayStats_roomArrival;
            //Đếm số phòng đã đi
            statisDash.todayActivity_Checked_Out = listReservationRoom.Where(r => r.BookingStatus == "CHECKOUT" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Count();
            //Đếm số phòng dự kiến đi
            statisDash.todayActivity_Due_Out = statisDash.todayStats_roomDueOut;
            //Đếm phòng có ngày đến=ngày đi=ngày hiện tại (chỉ lấy phòng có trạng thái CHECKIN + CHECKOUT)
            statisDash.todayActivity_Day_Use = listReservationRoom.Where(r => r.ArrivalDate >= datefrom && r.ArrivalDate < dateto && r.ArrivalDate.Value.Date == r.DepartureDate.Value.Date && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "CHECKOUT")).Count();

            //var CountAdulttt = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
            //   .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList();

            //var CountChildtt = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
            //  .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList();

            var CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            var CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            var CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });
            //var CountAduldChild1 = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            statisDash.hotelGuests_Expected_In_House_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            statisDash.hotelGuests_Expected_In_House_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());

            var Current_In_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Current_In_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Current_In_House = Current_In_Adult + Current_In_Children;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
              .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Due_To_Checkout_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Due_To_Checkout_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Due_To_Checkout = Due_To_Checkout_Children + Due_To_Checkout_Adult;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
             .Join(listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Due_To_Arrive_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Due_To_Arrive_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Due_To_Arrive = Due_To_Arrive_Adult + Due_To_Arrive_Children;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
           .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Staying_Over_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Staying_Over_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Staying_Over = Staying_Over_Adult + Staying_Over_Children;

            var Expected_In_House = Due_To_Arrive + statisDash.hotelGuests_Expected_In_House_Adult + statisDash.hotelGuests_Expected_In_House_Children;
            var Expected_In_House_Adult = Due_To_Arrive_Adult + statisDash.hotelGuests_Expected_In_House_Adult;
            var Expected_In_House_Children = Due_To_Arrive_Children + statisDash.hotelGuests_Expected_In_House_Children;

            var todayStats_roomOccupiedForecast = listReservationRoom.Where(r => r.ArrivalDate < dateto && r.DepartureDate >= datefrom && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "BOOKED" || r.BookingStatus == "CHECKOUT")).Count()
                                                - listReservationRoom.Where(r => r.ArrivalDate < datefrom && r.DepartureDate >= datefrom && r.DepartureDate < dateto && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "BOOKED" || r.BookingStatus == "CHECKOUT")).Count();

            double TotaltodayStats_Projected_Occupancy = 0;
            if (statisDash.todayStats_roomTotalRoomsToSell > 0)
            {
                TotaltodayStats_Projected_Occupancy = Convert.ToDouble(todayStats_roomOccupiedForecast) / statisDash.todayStats_roomTotalRoomsToSell * 100;
            }
            statisDash.todayStats_Projected_Occupancy = Math.Round(TotaltodayStats_Projected_Occupancy, 2);

            var Dirty_Occupied = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN")
                            .Join(roomList.Where(ro => ro.HouseStatus == "DIRTY"), l1 => l1.RoomId, l2 => l2.RoomId, (l1, l2) => new { }).ToList().Count();

            var Dirty_Variant = Math.Abs(roomList.Where(ro => ro.HouseStatus == "DIRTY").ToList().Count() - Dirty_Occupied);

            var retval = new
            {
                Dashboard = statisDash,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },
                Out_Of_Order = TotalrepairRoomCount,
                Total_Room_Available = TotalRoomCount,
                Dirty_Occupied = Dirty_Occupied,
                Dirty_Variant = Dirty_Variant,
                hotelGuests = new
                {
                    Current_In_House = Current_In_House
                    ,
                    Current_In_Adult = Current_In_Adult
                    ,
                    Current_In_Children = Current_In_Children
                    ,
                    Due_To_Checkout = Due_To_Checkout
                    ,
                    Due_To_Checkout_Adult = Due_To_Checkout_Adult
                    ,
                    Due_To_Checkout_Children = Due_To_Checkout_Children
                    ,
                    Due_To_Arrive = Due_To_Arrive
                    ,
                    Due_To_Arrive_Adult = Due_To_Arrive_Adult
                    ,
                    Due_To_Arrive_Children = Due_To_Arrive_Children
                    ,
                    Staying_Over = Staying_Over
                    ,
                    Staying_Over_Adult = Staying_Over_Adult
                    ,
                    Staying_Over_Children = Staying_Over_Children
                    ,
                    Expected_In_House = Expected_In_House
                    ,
                    Expected_In_House_Adult = Expected_In_House_Adult
                    ,
                    Expected_In_House_Children = Expected_In_House_Children
                },
            };
            //memCache.Add("STATUS_" + user.HotelId, retval, DateTimeOffset.UtcNow.AddHours(1));
            var cache = retval;
            memCache.AddByHotelId(user.HotelId, cacheKey, cache, DateTimeOffset.UtcNow.AddHours(1));
            return Ok(retval);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomTimeline")]
        public async Task<IHttpActionResult> getTimeline(DateTime date, int duration)
        {
            var memcache = new MemoryCacher();
            var user = Common.UserUtitily.getUserProfile();
            var cacheKey = "TIMELINE_" + user.HotelId + "_" + string.Format("{0:yyyyMMdd}", date) + "_" + duration;
            var timelineCache = memcache.GetValue(cacheKey);
            if (timelineCache != null)
                return Ok(timelineCache);
            var context = new ezCloudDataContext();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            date = date.AddMinutes(-currentHotel.TimeZoneOffset);
            var endDate = date.AddDays(duration);
            var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.IsHidden == false)
                 .Future().ToList().OrderBy(o=>o.OrderNumber);
            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false).
                 Select(rm => new
                 {
                     Room = rm,
                     RoomType = rm.RoomTypes,
                     rm.RoomRepairList
                 }).ToList();
            var roomTypes = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId).ToList();

            var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId!=null && (DateTime)r.ArrivalDate <= endDate && (DateTime)r.DepartureDate >= date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new
                   {
                       r.BookingStatus,
                       r.Adults,
                       r.ArrivalDate,
                       r.Child,
                       r.DepartureDate,
                       r.Reservations,
                       Travellers = new
                       {
                           r.Travellers.Fullname,
                           r.Travellers.TravellerId
                       },
                       r.RoomId,
                       r.ReservationRoomId,
                       r.TravellersList,
                       r.Foc,
                       r.DiscountPercentage,
                       r.DiscountFlat,
                       r.RoomPriceId,
                   }).ToList();

            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId &&
                rr.BookingStatus != "CANCELLED" && ((rr.ArrivalDate <= endDate && rr.DepartureDate >= date)))
                .Select(rr => new
                {
                    rr.BookingStatus,
                    IsGroupMaster = rr.IsGroupMaster == null ? false : rr.IsGroupMaster,
                    IsGroup = rr.Reservations.IsGroup == null ? false : rr.Reservations.IsGroup,
                    GroupColor = rr.Reservations.Color,
                    rr.Adults,
                    rr.ArrivalDate,
                    rr.Child,
                    rr.DepartureDate,
                    rr.Rooms,
                    rr.Reservations,
                    rr.Note,
                    rr.Price,
                    Travellers = new
                    {
                        rr.Travellers.Fullname,
                        rr.Travellers.TravellerId
                    },
                    rr.RoomPrices,
                    rr.RoomTypes,
                    rr.RoomId,
                    rr.RoomTypeId,
                    rr.ReservationRoomId,
                    rr.TravellersList,
                    rr.CancelReason,
                    rr.Foc,
                    rr.DiscountPercentage,
                    rr.DiscountFlat,
                    rr.RoomPriceId,
                    rr.Reservations.Company,
                    rr.Reservations.Source,
                    rr.Reservations.Market,
                    //rr.RoomExtraServicesList,
                    //rr.RoomExtraServiceItemsList,
                    //rr.PaymentsList,
                    rr.CreatedDate,
                    rr.CreatedUserId,
                    rr.CheckInDate,
                    rr.CheckInUserId,
                    rr.CheckOutDate,
                    rr.CheckOutUserId,
                    rr.CancelDate,
                    rr.CancelUserId,
                    rr.ReservationTravellersList
                    //rr.RoomMoveList
                }).ToList();
            var roomsList = rooms;

            List<int> rrIdList = new List<int>();

            foreach (var rr in reservationRooms)
            {
                rrIdList.Add(rr.ReservationRoomId);
            }

            var allRelatedRoomExtraServicesQuery = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRelatedPaymentsQuery = context.Payments.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomMovesQuery = context.RoomMove.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomExtraServiceItemsQuery = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allReservationTraveller = context.ReservationTravellers.Where(p=> rrIdList.Contains((int)p.ReservationRoomId));
            var listReservationTravellerExtraInformation = context.ReservationTravellerExtraInformation.Where(t => t.HotelId == user.HotelId)
               .Join(allReservationTraveller, rt => rt.ReservationTravellerId, rtei => rtei.ReservationTravellerId, (rt, rtei) => new { rt.ReservationTravellers.ReservationRoomId, rt.IsChild }).ToList();


            //var results2 = context.ExecuteQuery(allRelatedRoomExtraServicesQuery);
            //var results3 = context.ExecuteQuery(allRelatedPaymentsQuery);
            //var results4 = context.ExecuteQuery(allRoomMovesQuery);
            //var results5 = context.ExecuteQuery(allRoomExtraServiceItemsQuery);
            var allRoomExtraServiceList = allRelatedRoomExtraServicesQuery.ToList();
            var allRelatedPayments = allRelatedPaymentsQuery.ToList();
            var allRoomMoves = allRoomMovesQuery.ToList();
            var allRoomExtraServiceItemsList = allRoomExtraServiceItemsQuery.ToList();
            
            var statusColors = context.StatusColors.Where(sc => sc.HotelId == user.HotelId).ToList();
            // Add OC & Room avaibility by Room type
            //var inventoryByRoomTypeList = context.InventorybyRoomType(user.HotelId, date, endDate, "vn").ToList() ;
            var cache = new
            {
                reservationRooms = reservationRooms,
                roomList = roomList,
                rooms = roomsList,
                //roomBookingList = roomBookingList,
                BookingList= bookingList,
                roomTypes = roomTypes,
                RelatedPayments = allRelatedPayments,
                RoomMoves = allRoomMoves,
                RoomExtraServicesList = allRoomExtraServiceList,
                RoomExtraServiceItemsList = allRoomExtraServiceItemsList,
                statusColors = statusColors,
                ReservationTravellerExtraInformation = listReservationTravellerExtraInformation
                // inventoryByRoomTypeList = inventoryByRoomTypeList,
                //unassignRoom = UnassignRoom,
            };
            memcache.AddByHotelId(user.HotelId, cacheKey, cache, DateTimeOffset.UtcNow.AddHours(1));
            return Ok(cache);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AllCustomer")]
        public List<Travellers> GetAllCustomer()
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            List<Travellers> travellers = context.Travellers.Where(tvl => tvl.HotelId == user.HotelId).ToList();
            /*List<TravellerViewModel> travllerList = new List<TravellerViewModel>();
            foreach(var traveller in travellers)
            {
            }*/

            return travellers;
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AllPriceRate")]
        public List<RoomPrices> GetAllPriceRate()
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            List<RoomPrices> priceRates = context.RoomPrices.Where(pr => pr.HotelId == user.HotelId).ToList();
            return priceRates;
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomBookingList")]
        public List<ReservationRooms> AllRoomBooking(int roomId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            List<ReservationRooms> roomBookingList = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == roomId).ToList();
            return roomBookingList;
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AllRoom")]
        public List<Rooms> getAllRooms()
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            return context.Rooms.Where(room => room.HotelId == user.HotelId).ToList();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomTypes")]
        public List<RoomTypes> getAllRoomTypes()
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            return context.RoomTypes.Where(rt => rt.HotelId == user.HotelId).ToList();
        }

        public class UpdateBreakfastModel
        {
            public int RoomBreakfastId { get; set; }
            public bool IsBreakfast { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("UpdateBreakfast")]
        public async Task<IHttpActionResult> UpdateBreakfast(UpdateBreakfastModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var roomBreakfast = context.RoomBreakfast.Where(rb => rb.HotelId == user.HotelId && rb.RoomBreakfastId == model.RoomBreakfastId).FirstOrDefault();
            if (roomBreakfast != null)
            {
                roomBreakfast.UpdatedDate = DateTime.UtcNow;
                roomBreakfast.IsBreakfast = model.IsBreakfast;
                roomBreakfast.UpdatedUserId = user.UserId;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("Save")]
        public async Task<IHttpActionResult> SaveReservation(SaveRoomData data)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();

            //UPDATE RESERVATION
            if (data.room != null && data.room.ReservationRoomId != 0 && data.room.ReservationRoomId != 0)
            {
                if (data.room.ArrivalDate != null && data.room.DepartureDate != null)
                {
                    if (data.room.RoomId > 0)
                    {
                        var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != data.room.ReservationRoomId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (data.room.BookingStatus == "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && DateTime.UtcNow <= r.DepartureDate)) || (data.room.BookingStatus != "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate)))).FirstOrDefault();
                        if (conflictReservation != null)
                        {
                            ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                            return Content(HttpStatusCode.BadRequest, conflictReservation);
                        }

                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        // var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == data.room.RoomId).FirstOrDefault();
                    }
                    //ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId && rr.HotelId == user.HotelId).FirstOrDefault();
                    var oldRR = currentHotel.ReservationRoomsList.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                    if (oldRR != null)
                    {
                        CalculateRoomPrice model = new CalculateRoomPrice();
                        model.roomId = data.room.RoomId ?? 0;
                        model.reservationRoomId = data.room.ReservationRoomId;
                        model.adults = data.room.Adults;
                        model.children = data.room.Child;
                        model.RoomPriceId = data.room.RoomPriceId;
                        model.FOC = data.room.Foc;
                        model.DiscountFlat = data.room.DiscountFlat;
                        model.DiscountPercentage = (float)data.room.DiscountPercentage;
                        model.languageKeys = data.languageKeys;
                        model.Price = data.room.Price;

                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            //var oldPastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                            var oldPastCheckOut = oldRR.PastCheckOutList.Where(pt => pt.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                            if (oldPastCheckOut != null)
                            {
                                if (data.room.DepartureDate >= DateTime.UtcNow)
                                {
                                    return BadRequest("INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT");
                                }
                                else
                                {
                                    model.departureDate = data.room.DepartureDate ?? default(DateTime);
                                }
                            }
                            else
                            {
                                model.departureDate = DateTime.UtcNow;
                            }
                            model.arrivalDate = data.room.ArrivalDate ?? default(DateTime);
                        }

                        // CHECK IN PROCESS
                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            oldRR.ArrivalDate = DateTime.UtcNow;
                            oldRR.DepartureDate = data.room.DepartureDate;
                            oldRR.Adults = data.room.Adults;
                            oldRR.Child = data.room.Child;
                            oldRR.RoomId = data.room.RoomId;
                            oldRR.Note = data.room.Note;
                            oldRR.BookingStatus = data.room.BookingStatus;
                            oldRR.Price = data.room.Price;
                            oldRR.Foc = data.room.Foc;
                            oldRR.DiscountPercentage = data.room.DiscountPercentage;
                            oldRR.DiscountFlat = data.room.DiscountFlat;
                            oldRR.CheckInDate = DateTime.UtcNow;
                            oldRR.CheckInUserId = user.UserId;
                            // Update Houstatus = AVAILABLE if Room is DIRTY
                            //var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                            var rooms = oldRR.Rooms;
                            if (rooms != null && rooms.HouseStatus == "DIRTY")
                            {
                                rooms.HouseStatus = null;
                            }

                            if (data.company != null)
                            {
                                oldRR.Reservations.CompanyId = data.company.CompanyId;
                            }
                            if (data.source != null)
                            {
                                oldRR.Reservations.SourceId = data.source.SourceId;
                            }
                            if (data.market != null)
                            {
                                oldRR.Reservations.MarketId = data.market.MarketId;
                            }

                            
                        }

                        var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                        ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, user, context);
                        ReservationUtility.RebuildRoomCharges(dateRange, oldRR, user, context);
                        Notification.processNotificationCheckin(user, oldRR.Rooms.RoomName);

                        context.SubmitChanges();
                        // Consider only if hotel is using module "Channel Mananger"
                        // Room Available
                        ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

                        //Send sms to guest
                        SMSMobifone.sendSMSNotificationCheckin(oldRR);

                        Elastic.IndexLastAudit(context);
                        return Ok(data.room.ReservationRoomId);
                    }
                    else return BadRequest("RESERVATION_DOES_NOT_EXIST");
                }
                else
                    return BadRequest("PLEASE_SELECT_ARRIVAL/DEPARTURE_DATE");
            }

            // NEW RESERVATION
            else
            {
                if (data.room.ArrivalDate != null && data.room.DepartureDate != null)
                {
                    if (data.room.RoomId > 0)
                    {
                        var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate))).FirstOrDefault();
                        //var conflictReservation = currentHotel.ReservationRoomsList.Where(r => r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate))).FirstOrDefault();
                        if (conflictReservation != null)
                        {
                            ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                            return Content(HttpStatusCode.BadRequest, conflictReservation);
                        }

                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            //var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                            var conflictRoomRepair = currentHotel.RoomRepairList.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        if (data.room.BookingStatus == "BOOKED")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_BOOK_TO_REPAIRING_ROOM");
                            }
                        }
                        //var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == data.room.RoomId).FirstOrDefault();
                        var currentRoom = currentHotel.RoomsList.FirstOrDefault(rm => rm.RoomId == data.room.RoomId);
                        if (currentRoom != null && currentRoom.HouseStatus == "REPAIR")
                        {
                            if (currentRoom.RepairStartDate == null)
                            {
                                currentRoom.RepairStartDate = ((DateTime)SqlDateTime.MinValue);
                            }
                            if (currentRoom.RepairEndDate == null)
                            {
                                currentRoom.RepairEndDate = ((DateTime)SqlDateTime.MaxValue);
                            }
                            if (currentRoom.RepairStartDate < data.room.DepartureDate && data.room.ArrivalDate <= currentRoom.RepairEndDate)
                            {
                                return BadRequest("CAN_NOT_PROCESS_REPAIRING_ROOM");
                            }
                        }
                    }
                    Reservations res = null;

                    //Create new
                    if (data.room != null && data.room.ReservationId != null && data.room.ReservationId > 0)
                    {
                        //Has reservation
                        //res = context.Reservations.Where(r => r.ReservationId == data.room.ReservationId && r.HotelId == user.HotelId).FirstOrDefault();
                        res = currentHotel.ReservationsList.Where(r => r.ReservationId == data.room.ReservationId).FirstOrDefault();
                    }
                    if (res == null)
                    {
                        res = new Reservations();
                        res.HotelId = user.HotelId;
                        res.CreatedDate = DateTime.UtcNow;
                        res.ReservationNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATION");
                        context.Reservations.InsertOnSubmit(res);
                    }

                    if (data.source != null)
                    {
                        if (data.source.SourceId != 0)
                        {
                            res.SourceId = data.source.SourceId;
                        }
                        else
                        {
                            data.source.HotelId = user.HotelId;
                            data.source.CreatedDate = DateTime.UtcNow;
                            data.source.CreatedUserId = user.UserId;
                            data.source.IsAvailable = true;
                            context.Source.InsertOnSubmit(data.source);
                            res.Source = data.source;
                        }
                    }

                    if (data.company != null)
                    {
                        if (data.company.CompanyId != 0)
                        {
                            res.CompanyId = data.company.CompanyId;
                        }
                        else
                        {
                            data.company.HotelId = user.HotelId;
                            data.company.CreatedDate = DateTime.UtcNow;
                            data.company.CreatedUserId = user.UserId;
                            data.company.IsAvailable = true;
                            data.company.SourceId = data.company.SourceId != 0 ? data.company.SourceId : null;
                            context.Company.InsertOnSubmit(data.company);
                            res.Company = data.company;
                        }
                    }
                    if (data.market != null)
                    {
                        if (data.market.MarketId != 0)
                        {
                            res.MarketId = data.market.MarketId;
                        }
                        else
                        {
                            data.market.HotelId = user.HotelId;
                            data.market.CreatedDate = DateTime.UtcNow;
                            data.market.CreatedUserId = user.UserId;
                            data.market.IsAvailable = true;
                            context.Market.InsertOnSubmit(data.market);

                            res.Market = data.market;
                        }
                    }

                    data.room.Reservations = res;
                    data.room.HotelId = res.HotelId;
                    data.room.RoomId = (data.room.RoomId == 0) ? null : data.room.RoomId;
                    data.room.CreatedDate = DateTime.UtcNow;
                    data.room.CreatedUserId = user.UserId;
                    data.room.ReservationRoomNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATIONROOM");
                    if (data.room.BookingStatus == "CHECKIN")
                    {
                        // Update Houstatus = AVAILABLE if Room is DIRTY

                        //var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                        var rooms = currentHotel.RoomsList.Where(r => r.RoomId == data.room.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                        if (rooms != null)
                        {
                            rooms.HouseStatus = null;
                        }


                        data.room.ArrivalDate = DateTime.UtcNow;
                        data.room.CheckInDate = DateTime.UtcNow;
                        data.room.CheckInUserId = user.UserId;
                        //Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName + " ", user.HotelId, "NOTIFICATION_CHECKEDIN");
                        Notification.processNotificationCheckin(user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName);
                    }

                    if (data.customer != null)
                    {
                        var insertedTraveller = new Travellers();
                        if (data.customer.TravellerId > 0)
                        {
                            data.room.TravellerId = data.customer.TravellerId;
                            Travellers oldTraveller = context.Travellers.Where(tv => tv.HotelId == user.HotelId && tv.TravellerId == data.room.TravellerId).FirstOrDefault();
                            oldTraveller.Email = data.customer.Email;
                            oldTraveller.Fullname = data.customer.Fullname;
                            oldTraveller.Mobile = data.customer.Mobile;
                            oldTraveller.Birthday = data.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                            oldTraveller.IdentityNumber = data.customer.IdentityNumber;
                            oldTraveller.Gender = data.customer.Gender;
                            oldTraveller.Address = data.customer.Address;
                            oldTraveller.CountryId = data.customer.CountryId;
                            oldTraveller.HotelId = user.HotelId;
                            oldTraveller.ModifiedUserId = user.UserId;
                            oldTraveller.ModifiedDate = DateTime.UtcNow;
                            insertedTraveller = oldTraveller;
                        }
                        else
                        {
                            data.customer.HotelId = user.HotelId;
                            data.customer.Birthday = data.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                            data.customer.CreatedDate = DateTime.UtcNow;
                            data.customer.CreatedUserId = user.UserId;
                            if (data.customer.CountryId == null)
                            {
                                var country = context.Countries.First(c => c.CountryCode.ToLower() == "VN");
                                if (country != null)
                                {
                                    data.customer.CountryId = country.CountryId;
                                }
                            }
                            context.Travellers.InsertOnSubmit(data.customer);
                            insertedTraveller = data.customer;
                            data.room.Travellers = insertedTraveller;
                        }

                        context.ReservationRooms.InsertOnSubmit(data.room);

                        ReservationTravellers resTraveller = new ReservationTravellers();
                        resTraveller.ReservationRooms = data.room;
                        resTraveller.Travellers = insertedTraveller;
                        context.ReservationTravellers.InsertOnSubmit(resTraveller);

                        ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                        newRTEI.HotelId = user.HotelId;
                        newRTEI.ReservationTravellers = resTraveller;
                        newRTEI.IsChild = false;
                        context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                    }

                    if (data.sharerList != null && data.sharerList.Count > 0)
                    {
                        for (int i = 0; i < data.sharerList.Count; i++)
                        {
                            SharerViewModel sharerTemp = data.sharerList[i];
                            if (sharerTemp.customer.TravellerId == 0)
                            {
                                sharerTemp.customer.HotelId = user.HotelId;
                                sharerTemp.customer.CreatedUserId = user.UserId;
                                sharerTemp.customer.CreatedDate = DateTime.UtcNow;
                                context.Travellers.InsertOnSubmit(sharerTemp.customer);
                            }
                            else
                            {
                                //Travellers oldSharer = context.Travellers.Where(tv => tv.HotelId == user.HotelId && tv.TravellerId == sharerTemp.customer.TravellerId).FirstOrDefault();
                                var oldSharer = currentHotel.TravellersList.Where(tv => tv.TravellerId == sharerTemp.customer.TravellerId).FirstOrDefault();
                                oldSharer.Email = sharerTemp.customer.Email;
                                oldSharer.Fullname = sharerTemp.customer.Fullname;
                                oldSharer.Mobile = sharerTemp.customer.Mobile;
                                oldSharer.Birthday = sharerTemp.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                                oldSharer.IdentityNumber = sharerTemp.customer.IdentityNumber;
                                oldSharer.Gender = sharerTemp.customer.Gender;
                                oldSharer.Address = sharerTemp.customer.Address;
                                oldSharer.CountryId = sharerTemp.customer.CountryId;
                                oldSharer.ModifiedDate = DateTime.UtcNow;
                                oldSharer.ModifiedUserId = user.UserId;
                            }

                            ReservationTravellers newRT = new ReservationTravellers();
                            newRT.ReservationRoomId = data.room.ReservationRoomId;
                            newRT.Travellers = sharerTemp.customer;
                            context.ReservationTravellers.InsertOnSubmit(newRT);

                            ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                            newRTEI.HotelId = user.HotelId;
                            newRTEI.ReservationTravellers = newRT;
                            newRTEI.IsChild = sharerTemp.travellerExtraInfo.IsChild;
                            context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                        }
                    }

                    if (data.room.RoomPriceId == 0)
                    {
                        data.room.RoomPriceId = (int?)null;
                    }
                    if (data.room.RoomId == 0)
                    {
                        data.room.RoomId = (int?)null;
                    }
                    if (data.room.RoomTypeId == 0)
                    {
                        data.room.RoomTypeId = (int?)null;
                    }
                    if (data.paymentList != null && data.paymentList.Count > 0)
                    {
                        //var moneyList = context.Money.Where(ht => ht.HotelId == user.HotelId).ToList();
                        var moneyList = currentHotel.MoneyList.Where(ht => ht.HotelId == user.HotelId).ToList();
                        var paymentMethodList = context.PaymentMethods.Where(pm => pm.PaymentMethodId == pm.PaymentMethodId).ToList();
                        foreach (var payment in data.paymentList)
                        {
                            payment.ReservationRooms = data.room;
                            payment.CreatedUserId = user.UserId;
                            payment.HotelId = user.HotelId;
                            payment.Money = moneyList.FirstOrDefault(mn => mn.MoneyId == payment.MoneyId);
                            payment.PaymentMethods = paymentMethodList.FirstOrDefault(pm => pm.PaymentMethodId == payment.PaymentMethodId);
                            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
                            {
                                payment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, payment.PaymentTypeName);
                            }
                            context.Payments.InsertOnSubmit(payment);
                        }
                    }

                    if (data.roomRemarks != null && data.roomRemarks.Count > 0)
                    {
                        for (int i = 0; i < data.roomRemarks.Count; i++)
                        {
                            RoomRemarks roomRemark = new RoomRemarks();
                            roomRemark.HotelId = user.HotelId;
                            roomRemark.ReservationRooms = data.room;
                            roomRemark.RemarkEventId = data.roomRemarks[i].RemarkEventId;
                            roomRemark.Description = data.roomRemarks[i].Description;
                            roomRemark.IsCompleted = data.roomRemarks[i].IsCompleted;
                            roomRemark.IsDeleted = data.roomRemarks[i].IsDeleted;
                            roomRemark.CreatedDate = data.roomRemarks[i].CreatedDate;
                            roomRemark.CreatedUserId = user.UserId;
                            context.RoomRemarks.InsertOnSubmit(roomRemark);
                        }
                    }

                    if (data.postedItems != null && data.postedItems.ReservationRoomId == 0)
                    {
                        var roomExtraService = new RoomExtraServices();
                        roomExtraService.RoomExtraServiceName = data.postedItems.name;
                        roomExtraService.RoomExtraServiceDescription = data.postedItems.description;
                        roomExtraService.HotelId = user.HotelId;
                        roomExtraService.IsPaid = false;
                        roomExtraService.ReservationRoomId = data.postedItems.ReservationRoomId;
                        roomExtraService.CreatedUserId = user.UserId;
                        roomExtraService.CreatedDate = DateTime.UtcNow;
                        roomExtraService.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, roomExtraService.RoomExtraServiceName);
                        int count = 0;
                        decimal totalMoney = 0;
                        List<RoomExtraServiceItems> newItems = new List<RoomExtraServiceItems>();
                        var serviceItemList = "";
                        foreach (SelectedServiceItem item in data.postedItems.items)
                        {
                            //var realItem = context.ExtraServiceItems.Where(it => it.HotelId == user.HotelId && it.ExtraServiceItemId == item.item.ExtraServiceItemId).FirstOrDefault();
                            var realItem = currentHotel.ExtraServiceItemsList.Where(it => it.ExtraServiceItemId == item.item.ExtraServiceItemId).FirstOrDefault();
                            if (realItem != null)
                            {
                                count++;
                                totalMoney += (decimal)realItem.Price * item.quantity;
                                RoomExtraServiceItems ritem = new RoomExtraServiceItems();
                                ritem.Quantity = item.quantity;
                                ritem.ExtraServiceItemId = realItem.ExtraServiceItemId;
                                ritem.HotelId = realItem.HotelId;
                                ritem.Price = realItem.Price;
                                ritem.ReservationRoomId = data.postedItems.ReservationRoomId;
                                newItems.Add(ritem);
                                serviceItemList = serviceItemList + realItem.ExtraServiceItemName + "(" + item.quantity.ToString() + ") ";
                            }
                        }
                        if (count == 0) return BadRequest("No items selected");
                        roomExtraService.Amount = totalMoney;
                        context.RoomExtraServices.InsertOnSubmit(roomExtraService);
                    }

                    if (data.postedNoItem != null && data.postedNoItem.Count > 0)
                    {
                        foreach (var item in data.postedNoItem)
                        {
                            var resNoItem = new RoomExtraServices();
                            resNoItem.RoomExtraServiceName = item.RoomExtraServiceName;
                            resNoItem.RoomExtraServiceDescription = item.RoomExtraServiceDescription;
                            resNoItem.Amount = item.Amount;
                            resNoItem.Quantity = item.Quantity;
                            resNoItem.HotelId = user.HotelId;
                            resNoItem.IsPaid = false;
                            resNoItem.ReservationRooms = data.room;
                            resNoItem.CreatedUserId = user.UserId;
                            resNoItem.CreatedDate = DateTime.UtcNow;
                            resNoItem.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "EXTRA_SERVICES");
                            context.RoomExtraServices.InsertOnSubmit(resNoItem);
                        }
                    }

                    var dateRange = new DateRange(data.room.ArrivalDate.Value, data.room.DepartureDate.Value);
                    
                    context.SubmitChanges();

                    ReservationUtility.CreateRoomBreakfasts(dateRange, data.room, user, context);
                    ReservationUtility.CreateRoomCharges(dateRange, data.room, user, context);

                    Notification.processNotificationDiscountAtWalkin(data, user);



                    //Elastic.IndexLastAudit(context);

                    // Consider only if hotel is using module "Channel Mananger"
                    // Room Available
                    ReservationUtility.RebuildAvailableRoom(data.room, user, context);
                    //send notification if have payments
                    if (data.paymentList != null && data.paymentList.Count > 0)
                    {
                        foreach (var payment in data.paymentList)
                        {

                            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
                            {
                                PaymentModel paymentsModel = new PaymentModel();
                                paymentsModel.languageKeys = data.languageKeys;
                                paymentsModel.payment = payment;
                                Notification.processNotificationAddNewPayment(paymentsModel, user);
                            }

                        }
                    }

                    /*if (data.room.BookingStatus == "CHECKIN")
                    {
                        //Notification.processNotificationCheckin(user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName);
                    }
                    else*/ if (data.room.BookingStatus == "BOOKED")
                    {
                        SMSMobifone.sendSMSNotificationBooked(res.ReservationRoomsList.FirstOrDefault());

                        if (!data.room.RoomId.HasValue)
                        {
                            Notification.processNotificationBookedNan(user, res.ReservationNumber.Value, data.customer.Fullname , data.languageKeys["NOTIFICATION_BOOKED_NAN_CONTENT"].ToString());
                        }
                        else
                        {

                            Notification.processNotificationBooked( user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName, res.ReservationNumber.Value, data.customer.Fullname, data.languageKeys["NOTIFICATION_BOOKED_CONTENT"].ToString() );
                        }
                    }
                    Elastic.IndexLastAudit(context);
                    return Ok(data.room.ReservationRoomId);
                }
                else
                {
                    return BadRequest("Please select arrival/departure date!");
                }
            }
        }

        public class EditCheckInTimeModel
        {
            public int ReservationRoomId { get; set; }
            public DateTime NewArrivalDate { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessEditCheckInTime")]
        public async Task<IHttpActionResult> ProcessEditCheckInTime(EditCheckInTimeModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var oldRR = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            if (oldRR != null)
            {
                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != oldRR.ReservationRoomId && r.RoomId == oldRR.RoomId && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && oldRR.BookingStatus == "CHECKIN") || (r.ArrivalDate < oldRR.DepartureDate && model.NewArrivalDate <= r.DepartureDate))).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }

                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == oldRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && model.NewArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_EDIT_CHECK_IN_TIME_TO_REPAIRING_ROOM");
                }

                oldRR.ArrivalDate = model.NewArrivalDate;
                var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, user, context);
                ReservationUtility.RebuildRoomCharges(dateRange, oldRR, user, context);
            }
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessPastCheckOut")]
        public async Task<IHttpActionResult> ProcessPastCheckOut(PastCheckOutModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var oldRR = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            var RRTemp = new ReservationRooms();
            if (oldRR != null)
            {

                var arrivalDate = oldRR.ArrivalDate;
                var departureDate = oldRR.DepartureDate;
                var roomTypeId = oldRR.RoomTypeId;
                RRTemp.ArrivalDate = arrivalDate;
                RRTemp.DepartureDate = departureDate;
                RRTemp.RoomTypeId = roomTypeId;

                CalculateRoomPrice calculateRoomPrice = new CalculateRoomPrice();
                calculateRoomPrice.roomId = oldRR.RoomId ?? 0;
                calculateRoomPrice.reservationRoomId = oldRR.ReservationRoomId;
                calculateRoomPrice.arrivalDate = oldRR.ArrivalDate ?? default(DateTime);
                calculateRoomPrice.adults = oldRR.Adults;
                calculateRoomPrice.children = oldRR.Child;
                calculateRoomPrice.RoomPriceId = oldRR.RoomPriceId;
                calculateRoomPrice.FOC = oldRR.Foc;
                calculateRoomPrice.DiscountFlat = oldRR.DiscountFlat;
                calculateRoomPrice.DiscountPercentage = (float)oldRR.DiscountPercentage;
                calculateRoomPrice.languageKeys = null;
                calculateRoomPrice.Price = oldRR.Price;
                calculateRoomPrice.roomTypeId = (int)oldRR.RoomTypeId;

                if (model.ApplyCheckOutInThePast)
                {
                    var oldPastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == oldRR.ReservationRoomId).FirstOrDefault();
                    if (oldPastCheckOut != null)
                    {
                        context.PastCheckOut.DeleteOnSubmit(oldPastCheckOut);
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                        Notification.processNotificationPastCheckout(user, oldRR.Rooms.RoomName.ToString(), model);

                    }
                    calculateRoomPrice.departureDate = model.NewDepartureDate;
                    PastCheckOut pastCheckOut = new PastCheckOut();
                    pastCheckOut.HotelId = user.HotelId;
                    pastCheckOut.ReservationRoomId = oldRR.ReservationRoomId;
                    pastCheckOut.PastCheckOutUserId = user.UserId;
                    pastCheckOut.ActualCheckOutTime = DateTime.UtcNow;
                    pastCheckOut.PastCheckOutTime = model.NewDepartureDate;
                    pastCheckOut.CreatedDate = DateTime.UtcNow;
                    pastCheckOut.PastCheckOutReason = model.PastCheckOutReason;

                    var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(calculateRoomPrice);
                    pastCheckOut.PastTotalRoomPrice = planListDateRange.totalPrice;
                    calculateRoomPrice.departureDate = DateTime.UtcNow;
                    var planListDateRangeTemp = await RoomPriceUtilities.CalculateRoomPrice(calculateRoomPrice);
                    pastCheckOut.ActualTotalRoomPrice = planListDateRangeTemp.totalPrice;
                    oldRR.DepartureDate = model.NewDepartureDate;
                    context.PastCheckOut.InsertOnSubmit(pastCheckOut);
                    var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                    ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, user, context);
                    ReservationUtility.RebuildRoomCharges(dateRange, oldRR, user, context);
                    Notification.processNotificationPastCheckout(user, oldRR.Rooms.RoomName.ToString(), model);
                }
                else
                {
                    var oldPastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
                    if (oldPastCheckOut != null)
                    {
                        context.PastCheckOut.DeleteOnSubmit(oldPastCheckOut);
                    }
                }
                context.SubmitChanges();

                // Consider only if hotel is using module "Channel Mananger"
                // Room Available
                if (RRTemp != null)
                {
                    // Update matrix for original period 
                    ReservationUtility.RebuildAvailableRoom(RRTemp, user, context);
                }

                Common.Elastic.IndexLastAudit(context); 
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("HotelFormInvoice")]
        public async Task<IHttpActionResult> GetHotelFormInvoice()
        {
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var hotelFormRoomInvoice = context.HotelForm.Where(hf => hf.HotelId == currentClientUser.HotelId && hf.FormType == "RoomInvoice").FirstOrDefault();
            var hotelFormRoomReceipt = context.HotelForm.Where(hf => hf.HotelId == currentClientUser.HotelId && hf.FormType == "Receipt").FirstOrDefault();
            return Ok(new { hotelFormRoomInvoice = hotelFormRoomInvoice, hotelFormRoomReceipt = hotelFormRoomReceipt });
        }

        public class ProcessCopModel
        {
            public ReservationRooms ReservationRooms { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessCopyRR")]
        public async Task<IHttpActionResult> ProcessCopyRR(ProcessCopModel requests)
        {
            ReservationRooms model = requests.ReservationRooms;
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            if (oldRR != null)
            {
                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == model.RoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((model.ArrivalDate <= r.ArrivalDate && r.ArrivalDate <= model.DepartureDate) || (r.ArrivalDate <= model.ArrivalDate && model.DepartureDate <= r.DepartureDate) || (model.ArrivalDate <= r.DepartureDate && r.DepartureDate <= model.DepartureDate) || (model.ArrivalDate <= r.ArrivalDate && r.DepartureDate <= model.DepartureDate))).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }

                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == oldRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_COPY_RESERVATION_TO_REPAIRING_ROOM");
                }

                var newReservation = new Reservations()
                {
                    CreatedDate = DateTime.UtcNow,
                    HotelId = user.HotelId,
                    CreatedUserId = user.UserId,
                    CompanyId = oldRR.Reservations.CompanyId,
                    SourceId = oldRR.Reservations.SourceId,
                    MarketId = oldRR.Reservations.MarketId,
                    ReservationNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATION")
                };
                context.Reservations.InsertOnSubmit(newReservation);
                var newRR = new ReservationRooms()
                {
                    TravellerId = model.TravellerId,
                    HotelId = user.HotelId,
                    ArrivalDate = model.ArrivalDate,
                    DepartureDate = model.DepartureDate,
                    RoomId = model.RoomId != 0 ? model.RoomId : null,
                    Note = model.Note,
                    Reservations = newReservation,
                    Adults = model.Adults,
                    Child = model.Child,
                    BookingStatus = "BOOKED",
                    Price = model.Price,
                    RoomPriceId = model.RoomPriceId,
                    RoomTypeId = model.RoomTypeId,
                    CreatedDate = DateTime.UtcNow,
                    CreatedUserId = user.UserId,
                    ReservationRoomNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATIONROOM")
                };

                

                context.ReservationRooms.InsertOnSubmit(newRR);
                
                if (oldRR.ReservationTravellersList.Count > 0)
                {
                    foreach (var reservationTraveller in oldRR.ReservationTravellersList)
                    {
                        var rtTemp = new ReservationTravellers();
                        rtTemp.Travellers = reservationTraveller.Travellers;
                        rtTemp.ReservationRooms = newRR;
                        context.ReservationTravellers.InsertOnSubmit(rtTemp);
                        var rtExtraInfo = new ReservationTravellerExtraInformation();
                        rtExtraInfo.HotelId = user.HotelId;
                        rtExtraInfo.ReservationTravellers = rtTemp;
                        context.ReservationTravellerExtraInformation.InsertOnSubmit(rtExtraInfo);
                    }
                }

                context.SubmitChanges();
                
                // Consider only if hotel is using module "Channel Mananger"

                if (newRR.RoomId == null || newRR.RoomId == 0)
                {
                    Notification.processNotificationBookedNan(user, (int)newReservation.ReservationNumber, newRR.Travellers.Fullname, requests.languageKeys["NOTIFICATION_BOOKED_NAN_CONTENT"].ToString());
                }
                else
                {
                    var roomName = currentHotel.RoomsList.Where(R => R.HotelId == user.HotelId && R.RoomId == newRR.RoomId).FirstOrDefault();
                    //ReservationNumber = (ReservationNumber == null) ? 0 : ReservationNumber; 
                     
                    Notification.processNotificationBooked(user, roomName.RoomName, (int)newReservation.ReservationNumber, newRR.Travellers.Fullname, requests.languageKeys["NOTIFICATION_BOOKED_CONTENT"].ToString());
                    //Notification.processNotificationBooked(user, tmp, 19, "leo", "[USER] booked [ROOM], Reservation number [RESERVATION_NUMBER], guest [FULL_NAME]");
                }
                // Breakfast + RoomCharges
                var dateRange = new DateRange(model.ArrivalDate.Value, model.DepartureDate.Value);
                ReservationUtility.CreateRoomBreakfasts(dateRange, newRR, user, context);
                ReservationUtility.CreateRoomCharges(dateRange, newRR, user, context);

                // Room Available
                ReservationUtility.RebuildAvailableRoom(newRR, user, context);
                Elastic.IndexLastAudit(context);
            }
            //}
            return Ok();
        }
         

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessRoomMove")]
       public async Task<IHttpActionResult> ProcessRoomMove(RoomMoveModel model)
        {
            //var moveRoomMessage = "";
            //moveRoomMessage = model.languageKeys["NOTIFICATION_CHANGE_ROOM"] != null ? model.languageKeys["NOTIFICATION_CHANGE_ROOM"].ToString() : "";
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = UserUtitily.getUserProfile();

            ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();

            if (oldRR != null)
            {
                //ReservationRooms orgOldRR = oldRR.; // for process CMS 
                var arrivalDate = oldRR.ArrivalDate;
                var departureDate = oldRR.DepartureDate;
                var roomTypeId = oldRR.RoomTypeId;

                if (model.OldRoomId != model.NewRoomId)
                {
                    var conflictRoom = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId == oldRR.ReservationRoomId && r.RoomId == model.NewRoomId).FirstOrDefault();
                    if (conflictRoom != null)
                    {
                        return BadRequest("ROOM_ALREADY_HAS_A_RESERVATION_WITH_THE_SAME_ID");
                    }
                }
                //if (oldRR.BookingStatus == "CHECKIN")
                //{
                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == model.NewRoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((model.ArrivalDate <= r.ArrivalDate && r.ArrivalDate <= model.DepartureDate) || (r.ArrivalDate <= model.ArrivalDate && model.DepartureDate <= r.DepartureDate) || (model.ArrivalDate <= r.DepartureDate && r.DepartureDate <= model.DepartureDate) || (model.ArrivalDate <= r.ArrivalDate && r.DepartureDate <= model.DepartureDate))).FirstOrDefault();
                //var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId != oldRR.ReservationRoomId && r.RoomId == oldRR.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.ArrivalDate < oldRR.DepartureDate && DateTime.UtcNow <= r.DepartureDate))).FirstOrDefault();
                //var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == model.NewRoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && (r.BookingStatus == "CHECKIN" || (model.ArrivalDate <= r.ArrivalDate && r.ArrivalDate <= model.DepartureDate) || (r.ArrivalDate <= model.ArrivalDate && model.DepartureDate <= r.DepartureDate) || (model.ArrivalDate <= r.DepartureDate && r.DepartureDate <= model.DepartureDate) || (model.ArrivalDate <= r.ArrivalDate && r.DepartureDate <= model.DepartureDate))).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }

                //var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.RoomId == model.NewRoomId && rr.IsDeleted == false && (rr.RepairStartDate <= model.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.RoomId == model.NewRoomId && rr.IsDeleted == false && (rr.RepairStartDate <= model.DepartureDate && model.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_ROOM_MOVE_IN_REPAIRING_TIME");
                }
                RoomPrices newRoomPrice = new RoomPrices();
                if (model.NewRoomPriceId != 0)
                {
                    newRoomPrice = context.RoomPrices.Where(rp => rp.HotelId == currentClientUser.HotelId && rp.RoomTypeId == model.NewRoomTypeId && rp.RoomPriceId == model.NewRoomPriceId).FirstOrDefault();
                }
                else
                {
                    newRoomPrice = context.RoomPrices.Where(rp => rp.HotelId == currentClientUser.HotelId && rp.RoomTypeId == model.NewRoomTypeId).FirstOrDefault();
                }
                //}

                //if (oldRR.BookingStatus == "BOOKED")
                //{
                //    var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.RoomId == model.NewRoomId && rr.IsDeleted == false && (rr.RepairStartDate <= model.DepartureDate && model.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                //    if (conflictRoomRepair != null)
                //    {
                //        return BadRequest("CAN_NOT_ROOM_MOVE_IN_REPAIRING_TIME");
                //    }
                //}

                Rooms oldRoom = context.Rooms.Where(or => or.HotelId == currentClientUser.HotelId && or.RoomId == oldRR.RoomId).FirstOrDefault();

                if (oldRR.BookingStatus == "CHECKIN" )
                {
                    

                    RoomMove roomMove = new RoomMove();
                    roomMove.ReservationRoomId = oldRR.ReservationRoomId;
                    roomMove.MoveDate = DateTime.UtcNow;
                    roomMove.HotelId = currentClientUser.HotelId;
                    roomMove.OldRoomId = oldRR.RoomId;
                    roomMove.NewRoomId = model.NewRoomId;
                    roomMove.ModifiedBy = currentClientUser.UserId;
                    roomMove.Description = model.Description;

                    switch (model.UsePriceRateType)
                    {
                        case 0:
                            roomMove.OldRoomPriceId = oldRR.RoomPriceId;
                            roomMove.NewRoomPriceId = oldRR.RoomPriceId;
                            break;

                        case 1:
                            roomMove.OldRoomPriceId = oldRR.RoomPriceId;
                            roomMove.NewRoomPriceId = newRoomPrice.RoomPriceId;
                            oldRR.RoomPriceId = newRoomPrice.RoomPriceId;
                            oldRR.Price = newRoomPrice.FullDayPrice ?? 0.0M;

                            if (model.RoomMoveFee != 0)
                            {
                                RoomExtraServices roomExtraService = new RoomExtraServices();
                                roomExtraService.HotelId = currentClientUser.HotelId;
                                roomExtraService.ReservationRoomId = oldRR.ReservationRoomId;
                                roomExtraService.RoomExtraServiceName = "EXTRA_SERVICES";
                                roomExtraService.CreatedDate = DateTime.UtcNow;
                                roomExtraService.CreatedUserId = currentClientUser.UserId;
                                roomExtraService.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(currentClientUser.HotelId, roomExtraService.RoomExtraServiceName);
                                roomExtraService.Amount = model.RoomMoveFee;
                                roomExtraService.Quantity = 1;
                                roomExtraService.RoomExtraServiceDescription = model.languageKeys["ROOM_MOVE_EXTRA_SERVICES"].ToString();
                                context.RoomExtraServices.InsertOnSubmit(roomExtraService);
                            }

                            //if (newRoomPrice.UseHourlyPrice == false)
                            //{
                            //    var dateRange = new DateRange(oldRR.BookingStatus == "CHECKIN" ? (DateTime)oldRR.ArrivalDate : model.ArrivalDate, model.DepartureDate);
                            //    ReservationUtility.RebuildRoomCharges(dateRange, oldRR, currentClientUser, context);
                            //}
                            break;
                    }

                   

                    context.RoomMove.InsertOnSubmit(roomMove);

                    

                    // Update Houstatus = AVAILABLE if Room is DIRTY
                    var rooms = context.Rooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == model.NewRoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                    if (rooms != null)
                    {
                        rooms.HouseStatus = null;
                    }
                    /*
                    Rooms newRoom = context.Rooms.Where(or => or.HotelId == currentClientUser.HotelId && or.RoomId == model.NewRoomId).FirstOrDefault();
                    moveRoomMessage = moveRoomMessage.Replace("[USER]", currentClientUser.FullName);
                    moveRoomMessage = moveRoomMessage.Replace("[OLD_ROOM]", oldRoom.RoomName);
                    moveRoomMessage = moveRoomMessage.Replace("[NEW_ROOM]", newRoom.RoomName);

                    Notification.sendNotificationToDevice(currentClientUser.UserName.ToLower(), moveRoomMessage, currentClientUser.HotelId, "NOTIFICATION_WHEN_CHANGE_ROOM");
                    */
                    Notification.processNotificationRoomMove(model, currentClientUser, oldRR);
                }

                if (oldRR.BookingStatus == "BOOKED")
                {
                    if (model.UsePriceRateType == 1)
                    {
                        oldRR.RoomPriceId = newRoomPrice.RoomPriceId;
                        oldRR.Price = newRoomPrice.FullDayPrice ?? 0.0M;
                    }

                }

                oldRR.RoomId = model.NewRoomId;
                oldRR.RoomTypeId = model.NewRoomTypeId;
                
                //string logs = "Reservation info:Res No-" + oldRR.Reservations.ReservationNumber.ToString()
                //    + ", Booking status-" + oldRR.BookingStatus 
                //    + ", Arrival Date-" + oldRR.ArrivalDate.Value.ToString("dd/MM/yyyy HH:mm")
                //    + ", Model Arrival Date-" + model.ArrivalDate.ToString("dd/MM/yyyy HH:mm")
                //    + ", Departure Date-" + oldRR.DepartureDate.Value.ToString("dd/MM/yyyy HH:mm")
                //    +", Model Departure Date-" + model.DepartureDate.ToString("dd/MM/yyyy HH:mm");
                //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, logs);
                if (oldRR.BookingStatus == "BOOKED")
                { 
                     oldRR.ArrivalDate = model.ArrivalDate;
                     oldRR.DepartureDate = model.DepartureDate;

                    //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, "If oldRR.BookingStatus ==> BOOKED");

                }

                if (oldRR.BookingStatus == "CHECKIN")
                {
                    //oldRR.ArrivalDate = model.ArrivalDate;
                    oldRR.DepartureDate = model.DepartureDate;
                    //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, "If oldRR.BookingStatus ==> CHECKIN");
                }

                if (oldRoom != null && oldRR.BookingStatus != "BOOKED")
                {
                    oldRoom.HouseStatus = "DIRTY";
                }

                if (newRoomPrice.UseHourlyPrice == false && model.UsePriceRateType==1)
                {
                    context.ExecuteCommand("Delete RoomCharges where HotelId={0} and ReservationRoomId={1}", currentClientUser.HotelId, oldRR.ReservationRoomId);
                }

                context.SubmitChanges();
                if (oldRR.ArrivalDate != model.ArrivalDate || oldRR.DepartureDate != model.DepartureDate || newRoomPrice.UseHourlyPrice == false)
                {
                    // Rebuild RoomBreakfast and Room Charges

                    var dateRange = new DateRange(oldRR.BookingStatus == "CHECKIN" ? (DateTime)oldRR.ArrivalDate : model.ArrivalDate, model.DepartureDate);
                    ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, currentClientUser, context);
                    ReservationUtility.RebuildRoomCharges(dateRange, oldRR, currentClientUser, context);
                }

                //logs = "after change ==> Reservation info:Res No-" + oldRR.Reservations.ReservationNumber.ToString()
                //    + ", Booking status-" + oldRR.BookingStatus 
                //    + ", Arrival Date-" + oldRR.ArrivalDate.Value.ToString("dd/MM/yyyy HH:mm")
                //     + ", Model Arrival Date-" + model.ArrivalDate.ToString("dd/MM/yyyy HH:mm")
                //    + ", Departure Date-" + oldRR.DepartureDate.Value.ToString("dd/MM/yyyy HH:mm")
                //    + ", Model Departure Date-" + model.DepartureDate.ToString("dd/MM/yyyy HH:mm");
                //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, logs);

                Common.Elastic.IndexLastAudit(context);

                // Consider only if hotel is using module "Channel Mananger"
                // Room Availabl
                ReservationUtility.RebuildAvailableRoom(oldRR, currentClientUser, context);

                //logs = "after RebuildAvailableRoom ==> Reservation info:Res No-" + oldRR.Reservations.ReservationNumber.ToString()
                //   + ", Booking status-" + oldRR.BookingStatus
                //   + ", Arrival Date-" + oldRR.ArrivalDate.Value.ToString("dd/MM/yyyy HH:mm")
                //    + ", Model Arrival Date-" + model.ArrivalDate.ToString("dd/MM/yyyy HH:mm")
                //   + ", Departure Date-" + oldRR.DepartureDate.Value.ToString("dd/MM/yyyy HH:mm")
                //   + ", Model Departure Date-" + model.DepartureDate.ToString("dd/MM/yyyy HH:mm");
                //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, logs);

                // Update matrix for original period 
                var RRTemp = new ReservationRooms();
                RRTemp.ArrivalDate=arrivalDate;
                RRTemp.DepartureDate = departureDate;
                RRTemp.RoomTypeId = roomTypeId;
                ReservationUtility.RebuildAvailableRoom(RRTemp, currentClientUser, context);

                //logs = "after RebuildAvailableRoom 1==> Reservation info:Res No-" + oldRR.Reservations.ReservationNumber.ToString()
                // + ", Booking status-" + oldRR.BookingStatus
                // + ", Arrival Date-" + oldRR.ArrivalDate.Value.ToString("dd/MM/yyyy HH:mm")
                //  + ", Model Arrival Date-" + model.ArrivalDate.ToString("dd/MM/yyyy HH:mm")
                // + ", Departure Date-" + oldRR.DepartureDate.Value.ToString("dd/MM/yyyy HH:mm")
                // + ", Model Departure Date-" + model.DepartureDate.ToString("dd/MM/yyyy HH:mm");
                //NightAudit.RoomMoveWriteLog(currentClientUser.HotelId, logs);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAssignRoom")]
        public async Task<IHttpActionResult> ProcessAssignRoom(ReservationRooms model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var oldRR =
                context.ReservationRooms.FirstOrDefault(
                    rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId);
            if (oldRR != null)
            {
                //ReservationRooms orgOldRR = oldRR.; // for process CMS 
                var arrivalDate = oldRR.ArrivalDate;
                var departureDate = oldRR.DepartureDate;
                var roomTypeId = oldRR.RoomTypeId;

                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == model.RoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && (r.ArrivalDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= r.DepartureDate)).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == model.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_ASSIGN_ROOM_IN_REPAIRING_TIME");
                }
                oldRR.RoomTypeId = model.RoomTypeId;
                oldRR.RoomPriceId = model.RoomPriceId;
                oldRR.Price = model.Price;
                oldRR.RoomId = model.RoomId != 0 ? model.RoomId : null;
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);

                // Consider only if hotel is using module "Channel Mananger"
                // Room Available
                ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

                // Update matrix for original period 
                var RRTemp = new ReservationRooms();
                RRTemp.ArrivalDate = arrivalDate;
                RRTemp.DepartureDate = departureDate;
                RRTemp.RoomTypeId = roomTypeId;
                ReservationUtility.RebuildAvailableRoom(RRTemp, user, context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessUnassignRoom")]
        public async Task<IHttpActionResult> ProcessUnassignRoom(int RRID)
        {
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == RRID).FirstOrDefault();
            if (oldRR != null)
            {
                if (oldRR.RoomId == null)
                {
                    return BadRequest("NO_ROOM_ASSIGNED_TO_THIS_RESERVATION");
                }
                oldRR.RoomId = null;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RemoveSharer")]
        public async Task<IHttpActionResult> RemoveSharer(int sharerId, int reservationRoomId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            ReservationTravellers currentSharer = context.ReservationTravellers.Where(cs => cs.TravellerId == sharerId && cs.ReservationRoomId == reservationRoomId).FirstOrDefault();
            ReservationTravellerExtraInformation currentSharerExtraInfo = context.ReservationTravellerExtraInformation.Where(ex => ex.HotelId == user.HotelId && ex.ReservationTravellerId == currentSharer.ReservationTravellerId).FirstOrDefault();
            context.ReservationTravellerExtraInformation.DeleteOnSubmit(currentSharerExtraInfo);
            context.ReservationTravellers.DeleteOnSubmit(currentSharer);
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SetMainCustomer")]
        public async Task<IHttpActionResult> SetMainCustomer(int sharerId, int reservationRoomId)
        {
            var user = UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            ReservationRooms currentRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == reservationRoomId).FirstOrDefault();
            Travellers currentTraveler = context.Travellers.FirstOrDefault(tvl => tvl.HotelId == user.HotelId && tvl.TravellerId == sharerId);
            if (currentRR != null && currentTraveler != null)
            {
                var currentReservationTraveller = currentRR.ReservationTravellersList.FirstOrDefault(rt => rt.TravellerId == sharerId);
                context.ReservationTravellers.DeleteOnSubmit(currentReservationTraveller);

                var currentReservationTravellerExtra = currentReservationTraveller.ReservationTravellerExtraInformationList.FirstOrDefault();
                context.ReservationTravellerExtraInformation.DeleteOnSubmit(currentReservationTravellerExtra);

                currentRR.Travellers = currentTraveler;

                var newRT = new ReservationTravellers();
                newRT.ReservationRooms = currentRR;
                newRT.Travellers = currentTraveler;
                context.ReservationTravellers.InsertOnSubmit(newRT);

                var newRTEI = new ReservationTravellerExtraInformation();
                newRTEI.HotelId = user.HotelId;
                newRTEI.ReservationTravellers = newRT;
                newRTEI.IsChild = false;
                context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);

                context.SubmitChanges();
                Elastic.IndexLastAudit(context);

            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddSharer")]
        public async Task<IHttpActionResult> AddSharer(SharerViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            ReservationRooms oldRR = context.ReservationRooms.Where(old => old.HotelId == user.HotelId && old.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
            //New Sharer
            if (model.customer.TravellerId == 0)
            {
                model.customer.HotelId = user.HotelId;
                model.customer.CreatedDate = DateTime.UtcNow;
                model.customer.CreatedUserId = user.UserId;
                context.Travellers.InsertOnSubmit(model.customer);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);

                ReservationTravellers newRT = new ReservationTravellers();
                newRT.ReservationRoomId = model.reservationRoomId;
                newRT.TravellerId = model.customer.TravellerId;
                context.ReservationTravellers.InsertOnSubmit(newRT);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);

                ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                newRTEI.HotelId = user.HotelId;
                newRTEI.ReservationTravellerId = newRT.ReservationTravellerId;
                newRTEI.IsChild = model.travellerExtraInfo.IsChild;
                context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            // Old Sharer
            else
            {
                Travellers oldSharer = context.Travellers.Where(sh => sh.TravellerId == model.customer.TravellerId && sh.HotelId == user.HotelId).FirstOrDefault();
                if (oldSharer != null)
                {
                    oldSharer.Fullname = model.customer.Fullname;
                    oldSharer.Mobile = model.customer.Mobile;
                    oldSharer.Email = model.customer.Email;
                    oldSharer.IdentityNumber = model.customer.IdentityNumber;
                    oldSharer.Birthday = model.customer.Birthday;
                    oldSharer.Address = model.customer.Address;
                    oldSharer.Gender = model.customer.Gender;
                    oldSharer.CountryId = model.customer.CountryId;
                    oldSharer.ModifiedDate = DateTime.UtcNow;
                    oldSharer.ModifiedUserId = user.UserId;
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                }

                ReservationTravellers newRT = new ReservationTravellers();
                newRT.ReservationRoomId = model.reservationRoomId;
                newRT.TravellerId = oldSharer.TravellerId;
                context.ReservationTravellers.InsertOnSubmit(newRT);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);

                ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                newRTEI.HotelId = user.HotelId;
                newRTEI.ReservationTravellerId = newRT.ReservationTravellerId;
                newRTEI.IsChild = model.travellerExtraInfo.IsChild;
                context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }

            Elastic.IndexReservationRoom(model.reservationRoomId);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditSharerInfo")]
        public async Task<IHttpActionResult> EditSharerInfo(SharerViewModel model)
        {
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault();
            Travellers oldSharer = context.Travellers.Where(sh => sh.TravellerId == model.customer.TravellerId && sh.HotelId == user.HotelId).FirstOrDefault();
            if (oldSharer != null)
            {
                oldSharer.Fullname = model.customer.Fullname;
                oldSharer.Mobile = model.customer.Mobile;
                oldSharer.Email = model.customer.Email;
                oldSharer.IdentityNumber = model.customer.IdentityNumber;
                oldSharer.Birthday = model.customer.Birthday.HasValue ? model.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                oldSharer.Address = model.customer.Address;
                oldSharer.Gender = model.customer.Gender;
                oldSharer.CountryId = model.customer.CountryId;
                oldSharer.Note = model.customer.Note;
                oldSharer.ModifiedDate = DateTime.UtcNow;
                oldSharer.ModifiedUserId = user.UserId;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                if (model.travellerExtraInfo != null)
                {
                    ReservationTravellers oldRT = context.ReservationTravellers.Where(rt => rt.ReservationRoomId == model.reservationRoomId && rt.TravellerId == oldSharer.TravellerId).FirstOrDefault();
                    ReservationTravellerExtraInformation oldRTEI = context.ReservationTravellerExtraInformation.Where(ex => ex.HotelId == user.HotelId && ex.ReservationTravellerId == oldRT.ReservationTravellerId).FirstOrDefault();
                    oldRTEI.IsChild = model.travellerExtraInfo.IsChild;
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                }
                return Ok();
            }
            else
            {
                return BadRequest("ERROR");
            }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CheckIfSharerAChild")]
        public async Task<IHttpActionResult> CheckIfSharerAChild(int RRID, int travellerId)
        {
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            ReservationTravellers reservationTraveller = context.ReservationTravellers.Where(rt => rt.TravellerId == travellerId && rt.ReservationRoomId == RRID).FirstOrDefault();
            ReservationTravellerExtraInformation travellerExtra = context.ReservationTravellerExtraInformation.Where(ex => ex.HotelId == currentClientUser.HotelId && ex.ReservationTravellerId == reservationTraveller.ReservationTravellerId).FirstOrDefault();
            return Ok(travellerExtra.IsChild);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveAmendStay")]
        public async Task<IHttpActionResult> ProcessAmendStay(AmendStayModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == currentClientUser.HotelId);
            var currentRR = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
           
            var RRTemp = new ReservationRooms();

            if (currentRR != null)
            {
                var arrivalDate = currentRR.ArrivalDate;
                var departureDate = currentRR.DepartureDate;
                var roomTypeId = currentRR.RoomTypeId;
                RRTemp.ArrivalDate = arrivalDate;
                RRTemp.DepartureDate = departureDate;
                RRTemp.RoomTypeId = roomTypeId;

                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == currentRR.RoomId && r.ReservationRoomId != currentRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((model.arrivalDate <= r.ArrivalDate && r.ArrivalDate <= model.departureDate) || (r.ArrivalDate <= model.arrivalDate && model.departureDate <= r.DepartureDate) || (model.arrivalDate <= r.DepartureDate && r.DepartureDate <= model.departureDate) || (model.arrivalDate <= r.ArrivalDate && r.DepartureDate <= model.departureDate))).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.RoomId == currentRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= model.departureDate && model.arrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_AMEND_STAY_TO_REPAIRING_TIME");
                }
               

                if (currentRR.BookingStatus == "BOOKED")
                {
                    currentRR.ArrivalDate = model.arrivalDate;
                    currentRR.DepartureDate = model.departureDate;

                }

                if (currentRR.BookingStatus == "CHECKIN")
                {
                    //currentRR.ArrivalDate = model.arrivalDate;
                    currentRR.DepartureDate = model.departureDate;
                }
                
                currentRR.Adults = model.adults;
                currentRR.Child = model.child;

                // Rebuild RoomBreakfast and Room Charges
                var dateRange = new DateRange(currentRR.BookingStatus == "CHECKIN" ? (DateTime)currentRR.ArrivalDate : model.arrivalDate, model.departureDate);
                //var dateRange = new DateRange(model.arrivalDate, model.departureDate);
                ReservationUtility.RebuildRoomBreakfasts(dateRange, currentRR, currentClientUser, context);
                ReservationUtility.RebuildRoomCharges(dateRange, currentRR, currentClientUser, context);

            }

            context.SubmitChanges();
            Elastic.IndexLastAudit(context);

            // Consider only if hotel is using module "Channel Mananger"
            // Room Available
            ReservationUtility.RebuildAvailableRoom(currentRR, currentClientUser, context);

            if(RRTemp!=null)
            {
                // Update matrix for original period 
                ReservationUtility.RebuildAvailableRoom(RRTemp, currentClientUser, context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveRoomCharge")]
        public async Task<IHttpActionResult> SaveRoomCharge(EditRoomChargeModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var oldRoomCharge = context.RoomCharges.FirstOrDefault(rc => rc.HotelId == user.HotelId && rc.ReservationRoomId == model.ReservationRoomId && rc.RoomChargeId == model.RoomChargeId);
            if (oldRoomCharge != null)
            {
                if (model.Amount!=oldRoomCharge.Amount)
                    Notification.processNotificationSaveRoomCharge(model, user, oldRoomCharge);

                oldRoomCharge.Amount = model.Amount;
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveRoomChargeList")]
        public async Task<IHttpActionResult> SaveRoomChargeList(List<EditRoomChargeModel> model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomId = model[0].ReservationRoomId;
            var roomChargeList = context.RoomCharges.Where(rc => rc.HotelId == user.HotelId && rc.ReservationRoomId == reservationRoomId).ToList();
            if (roomChargeList.Count != model.Count)
            {
                return BadRequest("AN_EROR_OCCURRED.PLEASE_TRY_AGAIN");
            }
            else
            {
                Notification.processNotificationSaveListRoomCharge(model, user, roomChargeList);

                foreach (var roomCharge in roomChargeList)
                {
                    var roomChargeTemp = model.Where(rc => rc.RoomChargeId == roomCharge.RoomChargeId).FirstOrDefault();
                    if (roomChargeTemp != null)
                    {
                        roomCharge.Amount = roomChargeTemp.Amount;
                    }
                }
                
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveRoom")]
        public async Task<IHttpActionResult> SaveRoom(RoomViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();

            Rooms currentRoom = context.Rooms.Where(room => room.RoomId == model.RoomId).Single();

            currentRoom.RoomName = model.RoomName;
            currentRoom.RoomLocation = model.RoomLocation;
            currentRoom.RoomDescription = model.RoomDescription;
            currentRoom.RoomTypeId = model.RoomTypeId;

            currentRoom.HotelId = currentClientUser.HotelId;
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            Common.MemoryCacher.ClearStatusCache(currentClientUser.HotelId);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("Reservation")]
        public async Task<IHttpActionResult> GetReservation(int reservationRoomId)
        {
            var memcache = new Common.MemoryCacher();
            var reservationCache = memcache.GetValue("RESERVATION_" + reservationRoomId);
            if (reservationCache != null)
            {
                return Ok(reservationCache);
            }
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var currentHotel = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault();
            List<Countries> countries = context.Countries.Where(c => c.CountryId == c.CountryId).ToList();
            //var reservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == reservationRoomId)
            var reservationTemp = currentHotel.ReservationRoomsList.Where(r => r.ReservationRoomId == reservationRoomId).FirstOrDefault();
            var reservation = currentHotel.ReservationRoomsList.Where(r => r.ReservationRoomId == reservationRoomId)
                .Select(r => new
                {
                    room = r,
                    customer = r.Travellers,
                    reservationNumber = r.Reservations.ReservationNumber,
                    reservation = r.Reservations,
                    roomCharges = r.RoomChargesList
                }).FirstOrDefault();
            var applyPastCheckOut = false;
            var pastCheckOutReasonTemp = "";
            //var pastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == reservationRoomId).FirstOrDefault();
            var pastCheckOut = currentHotel.PastCheckOutList.Where(pt => pt.ReservationRoomId == reservationRoomId).FirstOrDefault();
            if (pastCheckOut != null)
            {
                applyPastCheckOut = true;
                pastCheckOutReasonTemp = pastCheckOut.PastCheckOutReason;
            }
            var pastCheckOutReason = pastCheckOutReasonTemp;

            if (reservation.customer.CountryId == null)
            {
                var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                reservation.customer.Countries = country;
                //context.SubmitChanges();
                //Common.Elastic.IndexLastAudit(context);
            }
            var roomInfo = new Rooms();
            if (reservation.room.RoomId != null)
            {
                //roomInfo = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == reservation.room.RoomId).FirstOrDefault();
                roomInfo = reservationTemp.Rooms;
            }
            //var roomTypeInfo = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.RoomTypeId == reservation.room.RoomTypeId).FirstOrDefault();
            var roomTypeInfo = reservationTemp.RoomTypes;

            //var planInfo = new RoomPrices();
            //if (reservation.room.RoomPriceId != null)
            //{
            //    planInfo = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId && rp.RoomPriceId == reservation.room.RoomPriceId).FirstOrDefault();
            //}
            var planInfo = reservationTemp.RoomPrices;
            //var roomExtraServices = context.RoomExtraServices.Where(i => i.HotelId == user.HotelId && i.ReservationRoomId == reservationRoomId).ToList();
            var roomExtraServices = reservationTemp.RoomExtraServicesList;
            var roomExtraServiceInfo = new List<RoomExtraServiceCreatedUserInfo>();
            foreach (var roomES in roomExtraServices)
            {
                RoomExtraServiceCreatedUserInfo infoTemp = new RoomExtraServiceCreatedUserInfo();
                infoTemp.RoomExtraServiceId = roomES.RoomExtraServiceId;
                infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == roomES.CreatedUserId).FirstOrDefault().UserName;
                if (roomES.IsDeleted)
                {
                    infoTemp.UserNameDeleted = context.AspNetUsers.Where(usr => usr.Id == roomES.DeletedBy).FirstOrDefault().UserName;
                }
                roomExtraServiceInfo.Add(infoTemp);
            }
            //var roomExtraServiceItems = context.RoomExtraServiceItems.Where(resi => resi.HotelId == user.HotelId && resi.ReservationRoomId == reservationRoomId).ToList();
            var roomExtraServiceItems = reservationTemp.RoomExtraServiceItemsList;
            var roomExtraServiceItemInfo = new List<RoomExtraServiceItemCreatedUserInfo>();
            foreach (var roomESI in roomExtraServiceItems)
            {
                if (roomESI.IsDeleted)
                {
                    RoomExtraServiceItemCreatedUserInfo infoTemp = new RoomExtraServiceItemCreatedUserInfo();
                    infoTemp.RoomExtraServiceItemId = roomESI.RoomExtraServiceItemId;
                    infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == roomESI.DeletedBy).FirstOrDefault().UserName;
                    roomExtraServiceItemInfo.Add(infoTemp);
                }
            }
            //var extraServices = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId).ToList();
            var extraServices = currentHotel.ExtraServiceTypesList;
            //var esCat = context.ExtraServiceCategories.Where(c => c.HotelId == user.HotelId && !c.IsHidden).ToList();
            var esCat = currentHotel.ExtraServiceCategoriesList.Where(c => !c.IsHidden);
            //var extraServiceItems = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && !r.IsHidden && esCat.Contains(r.ExtraServiceCategories)).ToList();
            var extraServiceItems = currentHotel.ExtraServiceItemsList.Where(r => !r.IsHidden && esCat.Contains(r.ExtraServiceCategories)).ToList();
            //var payments = context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == reservationRoomId).ToList();
            var payments = reservationTemp.PaymentsList;
            var paymentInfo = new List<PaymentInfo>();
            foreach (var payment in payments)
            {
                PaymentInfo infoTemp = new PaymentInfo();
                infoTemp.PaymentId = payment.PaymentId;
                infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == payment.CreatedUserId).FirstOrDefault().UserName;
                paymentInfo.Add(infoTemp);
            }

            //var currencies = context.Money.Where(mon => mon.HotelId == user.HotelId).ToList();
            var currencies = currentHotel.MoneyList;
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                //var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                var iso = currency.Currencies;
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
            var paymentMethods = context.PaymentMethods.Where(pay => pay.PaymentMethodId == pay.PaymentMethodId).ToList();
            //var sharer = context.ReservationTravellers.Where(rt => rt.ReservationRoomId == reservation.room.ReservationRoomId).ToList();
            var sharer = reservationTemp.ReservationTravellersList;
            List<SharerViewModel> sharerList = new List<SharerViewModel>();
            foreach (var sha in sharer)
            {
                SharerViewModel temp = new SharerViewModel();
                //temp.customer = context.Travellers.Where(s => s.HotelId == user.HotelId && s.TravellerId == sha.TravellerId).FirstOrDefault();
                temp.customer = currentHotel.TravellersList.Where(s => s.TravellerId == sha.TravellerId).FirstOrDefault();
                if (temp.customer!= null && temp.customer.CountryId == null)
                {
                    var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                    //temp.customer.CountryId = country.CountryId;
                    temp.customer.Countries = country;
                    //context.SubmitChanges();
                    //Common.Elastic.IndexLastAudit(context);
                }
                temp.reservationRoomId = reservationRoomId;

                //ReservationTravellerExtraInformation travellerExtra = context.ReservationTravellerExtraInformation.Where(ex => ex.HotelId == user.HotelId && ex.ReservationTravellerId == sha.ReservationTravellerId).FirstOrDefault();
                var travellerExtra = sha.ReservationTravellerExtraInformationList.FirstOrDefault();
                if (travellerExtra == null)
                {
                    travellerExtra = new ReservationTravellerExtraInformation();
                    travellerExtra.HotelId = user.HotelId;
                    travellerExtra.ReservationTravellerId = sha.ReservationTravellerId;
                    travellerExtra.IsChild = false;
                    context.ReservationTravellerExtraInformation.InsertOnSubmit(travellerExtra);
                    //context.SubmitChanges();
                    //Common.Elastic.IndexLastAudit(context);
                }
                temp.travellerExtraInfo = travellerExtra;
                sharerList.Add(temp);
            }



            //List<RoomRemarks> roomRemarks = context.RoomRemarks.Where(rrm => rrm.HotelId == user.HotelId && rrm.ReservationRoomId == reservationRoomId).ToList();
            var roomRemarks = reservationTemp.RoomRemarksList;
            //List<RoomBreakfast> roomBreakfast = context.RoomBreakfast.Where(rb => rb.HotelId == user.HotelId && rb.ReservationRoomId == reservationRoomId).ToList();
            var roomBreakfast = reservationTemp.RoomBreakfastList;

            //var market = context.Market.FirstOrDefault(mar => mar.HotelId == user.HotelId && mar.MarketId == reservation.reservation.MarketId);
            var market = reservation.reservation.Market;
            //var source = context.Source.FirstOrDefault(mar => mar.HotelId == user.HotelId && mar.SourceId == reservation.reservation.SourceId);
            var source = reservation.reservation.Source;
            //var company = context.Company.FirstOrDefault(mar => mar.HotelId == user.HotelId && mar.CompanyId == reservation.reservation.CompanyId);
            var company = reservation.reservation.Company;
            
            //check pre checkout 
            bool IsPreCheckOut = false;
            //var ChangeReservationStatus = context.ChangeReservationStatus.Where(m => m.ReservationRoomId == reservationRoomId && m.ActionCode == "PRE_CHECKOUT").ToList();
            var ChangeReservationStatus = reservationTemp.ChangeReservationStatusList.Where(m => m.ActionCode == "PRE_CHECKOUT").ToList();
            if (ChangeReservationStatus.Count() > 0)
            {
                IsPreCheckOut = true;
            }
            var cached = new
            {
                applyPastCheckOut = applyPastCheckOut,
                pastCheckOutReason = pastCheckOutReason,
                room = reservation.room,
                CMBookingId= reservation.reservation.CMBookingId,
                reservationNumber = reservation.reservationNumber,
                planInfo = planInfo,
                roomInfo = roomInfo,
                roomTypeInfo = roomTypeInfo,
                customer = reservation.customer,
                sharerList = sharerList,
                roomExtraServices = roomExtraServices,
                roomExtraServiceInfo = roomExtraServiceInfo,
                roomExtraServiceItems = roomExtraServiceItems,
                roomExtraServiceItemInfo = roomExtraServiceItemInfo,
                extraServices = extraServices,
                extraServiceItems = extraServiceItems,
                Payments = payments,
                PaymentInfo = paymentInfo,
                currencies = currencies,
                currenciesISO = currenciesISO,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName
                },
                paymentMethods = paymentMethods,
                countries = countries,
                roomRemarks = roomRemarks,
                roomBreakfast = roomBreakfast,
                company = company,
                source = source,
                market = market,
                roomCharges = reservation.roomCharges,
                IsPreCheckOut = IsPreCheckOut
            };
            memcache.AddByHotelId(user.HotelId, "RESERVATION_" + reservationRoomId, cached, DateTimeOffset.UtcNow.AddHours(1));
            return Ok(cached);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ExtraServiceList")]
        public async Task<IHttpActionResult> GetExtraServiceList()
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var es = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId).ToList();
            var escats = context.ExtraServiceCategories.Where(r => r.HotelId == user.HotelId && !r.IsHidden).ToList();
            var esitems = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && r.IsHidden == false && escats.Contains(r.ExtraServiceCategories)).ToList();

            return Ok(new ExtraServiceList
            {
                ExtraServiceTypes = es,
                ExtraServiceCategories = escats,
                ExtraServiceItems = esitems
            });
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ExtraServiceListByName")]
        public async Task<IHttpActionResult> GetReservation(string name, int reservationRoomId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var es = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId && r.ExtraServiceTypeName == name).FirstOrDefault();
            var escats = context.ExtraServiceCategories.Where(r => r.HotelId == user.HotelId && r.ExtraServiceTypeId == es.ExtraServiceTypeId && !r.IsHidden).ToList();
            // var esItemsAll =
            var esitems = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && r.ExtraServiceTypeId == es.ExtraServiceTypeId && !r.IsHidden && escats.Contains(r.ExtraServiceCategories)).ToList();
            var roomES = context.RoomExtraServices.Where(r => r.HotelId == user.HotelId && r.RoomExtraServiceName == name && r.ReservationRoomId == reservationRoomId).ToList();
            var roomESItems = context.RoomExtraServiceItems.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == reservationRoomId).ToList();

            return Ok(new ExtraServiceListByName
            {
                ExtraServiceTypes = es,
                ExtraServiceCategories = escats,
                ExtraServiceItems = esitems,
                RoomExtraServices = roomES,
                RoomExtraServiceItems = roomESItems
            });
        }

        private class ExtraServiceList
        {
            public List<ExtraServiceTypes> ExtraServiceTypes;
            public List<ExtraServiceCategories> ExtraServiceCategories;
            public List<ExtraServiceItems> ExtraServiceItems;
        }

        public class ExtraServiceByNameModel
        {
            public string name { get; set; }
            public int reservationRoomId { get; set; }
        }

        private class ExtraServiceListByName
        {
            public ExtraServiceTypes ExtraServiceTypes;
            public List<ExtraServiceCategories> ExtraServiceCategories;
            public List<ExtraServiceItems> ExtraServiceItems;
            public List<RoomExtraServices> RoomExtraServices;
            public List<RoomExtraServiceItems> RoomExtraServiceItems;
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CreateExtraService")]
        public async Task<IHttpActionResult> CreateExtraService(postedSelectedServiceItems items)
        {
            //var extraserviceMessage = "";
            //extraserviceMessage = items.languageKeys["NOTIFICATION_POST_EXTRASERVICE"] != null ? items.languageKeys["NOTIFICATION_POST_EXTRASERVICE"].ToString() : "";
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var reservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == items.ReservationRoomId).FirstOrDefault();
            if (reservation == null)
                return BadRequest("No reservation found!");
            RoomExtraServices res = new RoomExtraServices();
            res.RoomExtraServiceName = items.name;
            res.RoomExtraServiceDescription = items.description;
            res.HotelId = user.HotelId;
            res.IsPaid = false;
            res.ReservationRoomId = items.ReservationRoomId;
            res.CreatedUserId = user.UserId;
            res.CreatedDate = DateTime.UtcNow;
            res.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, res.RoomExtraServiceName);
            int count = 0;
            decimal totalMoney = 0; //decimal SumtotalMoney = 0;
            List<RoomExtraServiceItems> newItems = new List<RoomExtraServiceItems>();
            var serviceItemList = "";
            foreach (SelectedServiceItem item in items.items)
            {
                var realItem = context.ExtraServiceItems.Where(it => it.HotelId == user.HotelId && it.ExtraServiceItemId == item.item.ExtraServiceItemId).FirstOrDefault();
                if (realItem != null)
                {
                    count++;
                    totalMoney += (decimal)realItem.Price * item.quantity;
                    RoomExtraServiceItems ritem = new RoomExtraServiceItems();
                    ritem.Quantity = item.quantity;
                    ritem.ExtraServiceItemId = realItem.ExtraServiceItemId;
                    ritem.HotelId = realItem.HotelId;
                    ritem.Price = realItem.Price;
                    ritem.ReservationRoomId = items.ReservationRoomId;
                    newItems.Add(ritem);
                    serviceItemList = serviceItemList + realItem.ExtraServiceItemName + "(" + item.quantity.ToString() + ") ";
                }
            }
            if (count == 0) return BadRequest("No items selected");
            res.Amount = totalMoney;
            res.Quantity = 1;
            //SumtotalMoney += totalMoney;
            context.RoomExtraServices.InsertOnSubmit(res);
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            foreach (var item in newItems)
            {
                item.RoomExtraServiceId = res.RoomExtraServiceId;
                context.RoomExtraServiceItems.InsertOnSubmit(item);
            }
            /*
            var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == reservation.ReservationRoomId)
                   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
            var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == reservation.ReservationRoomId).FirstOrDefault().RoomId;
            var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
            var room_resno = "";
            if (roomId != null)
            {
                room_resno = items.languageKeys["ROOM"] != null ? items.languageKeys["ROOM"].ToString() : "";
            }
            else
            {
                room_resno = items.languageKeys["RES_NO"] != null ? items.languageKeys["RES_NO"].ToString() : "";
            }
            var defaultMoneyId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().DefaultMoneyId;
            var money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
            if (money == null) money = "VND";
            var spaymentAmount = Math.Abs(Convert.ToDecimal(SumtotalMoney)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
            extraserviceMessage = extraserviceMessage.Replace("[USER]", user.FullName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM]", roomName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
            extraserviceMessage = extraserviceMessage + " : " + serviceItemList + " (" + money + " " + spaymentAmount + ")";

            Notification.sendNotificationToDevice(user.UserName.ToLower(), extraserviceMessage, user.HotelId, "NOTIFICATION_WHEN_POST_EXTRASERVICE");
            */

            Notification.processNotificationCreateExtraService(items, user, reservation);
            
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            //Elastic.IndexReservationRoom(items.ReservationRoomId);
            return Ok(items);
        }

        #region QuickCheckout

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("QuickCreateExtraService")]
        public async Task<IHttpActionResult> QuickCreateExtraService(postedSelectedServiceItems items)
        {
            var user = Common.UserUtitily.getUserProfile(); var context = new ezCloudDataContext();
            var reservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == items.ReservationRoomId).FirstOrDefault();
            if (reservation == null)
                return BadRequest("No reservation found!");
            var serviceItemList = "";
            decimal SumtotalMoney = 0;
            foreach (SelectedServiceItem item in items.items)
            {
                if (item.ExtraServiceTypeName != "EXTRA_SERVICES")
                {
                    RoomExtraServices res = new RoomExtraServices();
                    res.RoomExtraServiceName = item.ExtraServiceTypeName;
                    res.HotelId = user.HotelId; res.IsPaid = false;
                    res.ReservationRoomId = items.ReservationRoomId;
                    res.CreatedUserId = user.UserId; res.CreatedDate = DateTime.UtcNow;
                    res.RoomExtraServiceDescription = item.ExtraServiceTypeName + " res:#" + items.ReservationRoomId + " room:#" + reservation.RoomId;
                    res.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, res.RoomExtraServiceName);
                    int count = 0; decimal totalMoney = 0;
                    List<RoomExtraServiceItems> newItems = new List<RoomExtraServiceItems>();
                    var realItem = context.ExtraServiceItems.Where(it => it.HotelId == user.HotelId && it.ExtraServiceItemId == item.item.ExtraServiceItemId).FirstOrDefault();
                    if (realItem != null)
                    {
                        if (realItem.IsChangeable == false && realItem.Price != item.item.Price)
                        {
                            return BadRequest("ERROR");
                        }
                        count++;
                        totalMoney += (decimal)item.item.Price * item.quantity;
                        RoomExtraServiceItems ritem = new RoomExtraServiceItems();
                        ritem.Quantity = item.quantity;
                        ritem.ExtraServiceItemId = realItem.ExtraServiceItemId;
                        ritem.HotelId = realItem.HotelId;
                        ritem.Price = (decimal)item.item.Price;
                        ritem.ReservationRoomId = items.ReservationRoomId;
                        newItems.Add(ritem);
                        serviceItemList += realItem.ExtraServiceItemName + "(" + item.quantity.ToString() + ") ";
                        int currentIndex = items.items.IndexOf(item);
                        if (items.items.Count() > 0 && currentIndex < items.items.Count() - 1)
                        {
                            serviceItemList += ", ";
                        }
                    }
                    if (count == 0) return BadRequest("No items selected");
                    res.Amount = totalMoney;
                    res.Quantity = 1;
                    SumtotalMoney += totalMoney;
                    context.RoomExtraServices.InsertOnSubmit(res);
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                    foreach (var itemTmp in newItems)
                    {
                        itemTmp.RoomExtraServiceId = res.RoomExtraServiceId;
                        context.RoomExtraServiceItems.InsertOnSubmit(itemTmp);
                    }
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                }
            }
            Notification.processNotificationCreateExtraService(items, user, reservation);
            return Ok();
        }

        #endregion QuickCheckout

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CreateExtraServiceNoItem")]
        public async Task<IHttpActionResult> CreateExtraServiceNoItem(ExtraServiceNoItemModel model)
        {
            //var extraserviceMessage = "";
            //extraserviceMessage = model.languageKeys["NOTIFICATION_POST_EXTRASERVICE"] != null ? model.languageKeys["NOTIFICATION_POST_EXTRASERVICE"].ToString() : "";
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var reservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            if (reservation == null)
                return BadRequest("No reservation found!");
            RoomExtraServices res = new RoomExtraServices();
            res.RoomExtraServiceName = model.RoomExtraServiceName;
            res.RoomExtraServiceDescription = model.RoomExtraServiceDescription;
            res.Amount = model.Amount;
            res.Quantity = model.Quantity==0?1:model.Quantity;
            res.HotelId = user.HotelId;
            res.IsPaid = false;
            res.ReservationRoomId = model.ReservationRoomId;
            res.CreatedUserId = user.UserId;
            res.CreatedDate = DateTime.UtcNow;
            res.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "EXTRA_SERVICES");
            context.RoomExtraServices.InsertOnSubmit(res);
            /*
            var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == reservation.ReservationRoomId)
                   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
            var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == reservation.ReservationRoomId).FirstOrDefault().RoomId;
            var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
            var room_resno = "";
            if (roomId != null)
            {
                room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
            }
            else
            {
                room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
            }

            extraserviceMessage = extraserviceMessage.Replace("[USER]", user.FullName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM]", roomName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
            var defaultMoneyId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().DefaultMoneyId;
            var money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
            if (money == null) money = "VND";
            var spaymentAmount = Math.Abs(Convert.ToDecimal(model.Amount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
            //extraserviceMessage = extraserviceMessage + " : " + model.RoomExtraServiceDescription + "(" + Math.Abs(Convert.ToDecimal(model.Amount)).ToString("0,0", CultureInfo.InvariantCulture) + ")";

            extraserviceMessage = extraserviceMessage + " : " + model.RoomExtraServiceDescription + "(" + money + " " + spaymentAmount + ")";

            Notification.sendNotificationToDevice(user.UserName.ToLower(), extraserviceMessage, user.HotelId, "NOTIFICATION_WHEN_POST_EXTRASERVICE");
            */
            Notification.processNotificationCreateExtraServiceNoItem(model, user, reservation);
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            //Elastic.IndexReservationRoom(model.ReservationRoomId);
            return Ok();
        }

        public class SelectedServiceItem
        {
            private int _quantity;
            public string ExtraServiceTypeName;
            public double Price;

            public int quantity
            {
                get { return _quantity; }
                set { _quantity = value; }
            }

            public ExtraServiceItems item;
        }

        public class postedSelectedServiceItems
        {
            public int ReservationRoomId;
            public string description;
            public string name;
            public List<SelectedServiceItem> items;
            public Hashtable languageKeys { get; set; }
        }

        public class ExtraServiceNoItemModel
        {
            public int ReservationRoomId { get; set; }
            public string RoomExtraServiceName { get; set; }
            public string RoomExtraServiceDescription { get; set; }
            public decimal Amount { get; set; }
            public int Quantity { set; get; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddPayment")]
        public async Task<IHttpActionResult> AddPayment(PaymentModel payments)
        {
            var user = Common.UserUtitily.getUserProfile();
            var payment = payments.payment;
            var context = new ezCloudDataContext();
            payment.HotelId = user.HotelId;
            payment.CreatedDate = DateTime.UtcNow;
            payment.CreatedUserId = user.UserId;

            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
            {
                payment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, payment.PaymentTypeName);
                /*
                var paymentMessage = "";

                if (payment.PaymentTypeName == "NEW_PAYMENT")
                {
                    paymentMessage = payments.languageKeys["NOTIFICATION_NEWPAYMENT"] != null ? payments.languageKeys["NOTIFICATION_NEWPAYMENT"].ToString() : "";
                }
                else if (payment.PaymentTypeName == "DEPOSIT")
                {
                    paymentMessage = payments.languageKeys["NOTIFICATION_DEPOSIT"] != null ? payments.languageKeys["NOTIFICATION_DEPOSIT"].ToString() : "";
                }
                else if (payment.PaymentTypeName == "REFUND")
                {
                    paymentMessage = payments.languageKeys["NOTIFICATION_REFUND"] != null ? payments.languageKeys["NOTIFICATION_REFUND"].ToString() : "";
                }
                var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == payment.ReservationRoomId)
                    .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                var money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == payment.MoneyId).FirstOrDefault().MoneyName;
                var paymethodname = context.PaymentMethods.Where(m => m.PaymentMethodId == payment.PaymentMethodId).FirstOrDefault().PaymentMethodName;
                var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == payment.ReservationRoomId).FirstOrDefault().RoomId;
                var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                var room_resno = "";
                if (roomId != null)
                {
                    room_resno = payments.languageKeys["ROOM"] != null ? payments.languageKeys["ROOM"].ToString() : "";
                }
                else
                {
                    room_resno = payments.languageKeys["RES_NO"] != null ? payments.languageKeys["RES_NO"].ToString() : "";
                }

                //var amount = Math.Abs(Convert.ToDecimal(payment.Amount));
                decimal paymentAmount = 0;
                if (payment.AmountInSpecificMoney != null)
                {
                    paymentAmount = Math.Abs(Convert.ToDecimal(payment.AmountInSpecificMoney)); //(decimal)payments.payment.AmountInSpecificMoney;
                }
                else
                {
                    paymentAmount = Math.Abs(Convert.ToDecimal(payment.Amount));
                }

                paymentMessage = paymentMessage.Replace("[USER]", user.FullName);

                paymentMessage = paymentMessage.ToString().Replace("[PAYMENTMETHOD]", payments.languageKeys[paymethodname] != null ? payments.languageKeys[paymethodname].ToString() : "");
                //paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " +Math.Abs(Convert.ToDecimal(paymentAmount)).ToString("0,0", CultureInfo.InvariantCulture));

                var spaymentAmount = Math.Abs(Convert.ToDecimal(paymentAmount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " + spaymentAmount);
                paymentMessage = paymentMessage.ToString().Replace("[ROOM]", roomName);
                paymentMessage = paymentMessage.ToString().Replace("[ROOM_RESNO]", room_resno);

                Notification.sendNotificationToDevice(user.UserName.ToLower(), paymentMessage, user.HotelId, "NOTIFICATION_WHEN_POST_PAYMENT");
                */
                Notification.processNotificationAddNewPayment(payments, user);

                context.Payments.InsertOnSubmit(payment);
            }

            //Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == oldRR.RoomId).FirstOrDefault().RoomName, user.HotelId, "NOTIFICATION_CHECKEDIN");

            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            return Ok(context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == payment.ReservationRoomId).ToList());
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DeletePayment")]
        public async Task<IHttpActionResult> PostDeletePayment(PaymentModel payments)
        {
            var user = Common.UserUtitily.getUserProfile();
            var payment = payments.payment;
            var context = new ezCloudDataContext();
            var oldPayment = context.Payments.Where(p => p.HotelId == user.HotelId && p.PaymentId == payment.PaymentId).FirstOrDefault();
            if (oldPayment == null)
            {
                return BadRequest("Payment does not exist!");
            }
            else
            {
                

                Payments deletedPayment = new Payments();

                deletedPayment = payment;
                deletedPayment.PaymentDescription = payment.PaymentDescription;
                deletedPayment.Amount = (payment.PaymentTypeName == "REFUND") ? payment.Amount : -payment.Amount;
                deletedPayment.CreatedDate = DateTime.UtcNow;
                deletedPayment.PaymentTypeName = "DELETED";
                deletedPayment.CreatedUserId = user.UserId;
                // deletedPayment.RefPaymentId = null;

                context.Payments.InsertOnSubmit(deletedPayment);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                oldPayment.RefPaymentId = deletedPayment.PaymentId;
                
                Notification.processNotificationDeletePayment(payments, user);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);

                if (oldPayment.IsPaymentGroup == true)
                {
                    var groupPayment = context.Payments.Where(p => p.HotelId == user.HotelId && p.IsPaymentGroup == true && p.PaymentNumber == oldPayment.PaymentNumber && p.RefPaymentId == null).ToList();
                    if (groupPayment.Count == 0)
                    {
                        oldPayment.IsPaymentGroupDeleted = true;
                        oldPayment.PaymentGroupCreatedDate = DateTime.UtcNow;
                        oldPayment.PaymentGroupCreatedUserId = user.UserId;
                    }
                    context.SubmitChanges();
                    Elastic.IndexLastAudit(context);
                }
            }
            //context.Payments.DeleteOnSubmit(oldPayment);
            //context.SubmitChanges();
            //Common.Elastic.IndexLastAudit(context);
            return Ok(context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == payment.ReservationRoomId).ToList());
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ApplyDiscount")]
        public async Task<IHttpActionResult> ApplyDiscount(ApplyDiscountModel model)
        {
            //var discountMessage = "";

            //if (model.FOC)
            //{
            //    discountMessage = model.languageKeys["NOTIFICATION_FREE_OF_CHARGE"] != null ? model.languageKeys["NOTIFICATION_FREE_OF_CHARGE"].ToString() : "";
            //}
            //else
            //{
            //    discountMessage = model.languageKeys["NOTIFICATION_DISCOUNT_ROOM_PRICE"] != null ? model.languageKeys["NOTIFICATION_DISCOUNT_ROOM_PRICE"].ToString() : "";
            //}
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();

            var currentRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
            if (currentRR != null)
            {
                currentRR.Foc = model.FOC;
                currentRR.DiscountPercentage = model.DiscountPercentage;
                currentRR.DiscountFlat = model.DiscountFlat;

                //var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == currentRR.ReservationRoomId)
                //   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                //var hotel = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault();
                //var money = context.Money.Where(m => m.MoneyId == hotel.DefaultMoneyId).FirstOrDefault().MoneyName;
                //var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == currentRR.ReservationRoomId).FirstOrDefault().RoomId;
                //var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                //var room_resno = "";
                //if (roomId != null)
                //{
                //    room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                //}
                //else
                //{
                //    room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                //}

                //discountMessage = discountMessage.Replace("[USER]", user.FullName);
                //discountMessage = discountMessage.ToString().Replace("[ROOM]", roomName);
                //discountMessage = discountMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                //if (model.DiscountFlat > 0)
                //{
                //    var spaymentAmount = Math.Abs(Convert.ToDecimal(model.DiscountFlat)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                //    discountMessage = discountMessage.ToString().Replace("[DISCOUNT_FLAT]", money + " " + spaymentAmount);
                //}
                //else
                //{
                //    discountMessage = discountMessage.ToString().Replace("[DISCOUNT_FLAT]", "");
                //}

                //if (model.DiscountPercentage > 0)
                //{
                //    discountMessage = discountMessage.ToString().Replace("[DISCOUNT_PERCENTAGE]", model.DiscountPercentage.ToString() + " %");
                //}
                //else
                //{
                //    discountMessage = discountMessage.ToString().Replace("[DISCOUNT_PERCENTAGE]", "");
                //}

                //if (model.DiscountFlat != 0 || model.DiscountPercentage != 0 || model.FOC)
                //{
                //    Notification.sendNotificationToDevice(user.UserName.ToLower(), discountMessage, user.HotelId, "NOTIFICATION_WHEN_DISCOUNT_ROOM_PRICE");
                //}
                Notification.processNotificationDiscount(model, user);

                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            Common.MemoryCacher.ClearStatusCache(user.HotelId);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DeleteExtraServiceItem")]
        public async Task<IHttpActionResult> PostDeleteExtraServiceItem(deletedSelectedServiceItems item)
        {
            //var extraserviceMessage = "";
            //extraserviceMessage = item.languageKeys["NOTIFICATION_DELETE_EXTRASERVICE"] != null ? item.languageKeys["NOTIFICATION_DELETE_EXTRASERVICE"].ToString() : "";

            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var oldItem = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && p.RoomExtraServiceItemId == item.roomExtraServiceItems.RoomExtraServiceItemId).FirstOrDefault();
            //var serviceItemList = "";
            if (oldItem == null)
            {
                return BadRequest("Item does not exist!");
            }
            else
            {
                oldItem.DeletedReason = item.roomExtraServiceItems.DeletedReason;
                oldItem.DeletedDate = DateTime.UtcNow;
                oldItem.DeletedBy = user.UserId;
                oldItem.IsDeleted = true;
                RoomExtraServices roomES = context.RoomExtraServices.Where(res => res.HotelId == user.HotelId && res.RoomExtraServiceId == item.roomExtraServiceItems.RoomExtraServiceId).FirstOrDefault();
                roomES.Amount -= oldItem.Quantity * oldItem.Price;
                //serviceItemList = serviceItemList + oldItem.ExtraServiceItems.ExtraServiceItemName + "(" + oldItem.Quantity.ToString() + ") ";
            }
            /*
            var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == oldItem.ReservationRoomId)
                   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
            var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == oldItem.ReservationRoomId).FirstOrDefault().RoomId;
            var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
            var room_resno = "";
            if (roomId != null)
            {
                room_resno = item.languageKeys["ROOM"] != null ? item.languageKeys["ROOM"].ToString() : "";
            }
            else
            {
                room_resno = item.languageKeys["RES_NO"] != null ? item.languageKeys["RES_NO"].ToString() : "";
            }

            extraserviceMessage = extraserviceMessage.Replace("[USER]", user.FullName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM]", roomName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
            extraserviceMessage = extraserviceMessage + " : " + serviceItemList;

            Notification.sendNotificationToDevice(user.UserName.ToLower(), extraserviceMessage, user.HotelId, "NOTIFICATION_WHEN_DELETE_EXTRASERVICE");
            */
            Notification.processNotificationDeleteExtraserviceItems(item, user, oldItem);

            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DeleteExtraService")]
        public async Task<IHttpActionResult> PostDeleteExtraService(deletedSelectedServices res)
        {
            //var extraserviceMessage = "";
            //extraserviceMessage = res.languageKeys["NOTIFICATION_DELETE_EXTRASERVICE"] != null ? res.languageKeys["NOTIFICATION_DELETE_EXTRASERVICE"].ToString() : "";
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var oldRES = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && p.RoomExtraServiceId == res.roomExtraServices.RoomExtraServiceId).FirstOrDefault();
            //var serviceItemList = "";
            if (oldRES == null)
            {
                return BadRequest("Service does not exist!");
            }
            else
            {
                oldRES.DeletedReason = res.roomExtraServices.DeletedReason;
                oldRES.DeletedDate = DateTime.UtcNow;
                oldRES.DeletedBy = user.UserId;
                oldRES.IsDeleted = true;
                // oldRES.Amount = 0;
                /*
                var defaultMoneyId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().DefaultMoneyId;
                var money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
                if (money == null) money = "VND";
                var spaymentAmount = Math.Abs(Convert.ToDecimal(res.roomExtraServices.Amount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                serviceItemList = serviceItemList + res.roomExtraServices.RoomExtraServiceDescription + " (" + money + " " + spaymentAmount + ") ";
                */
            }
            /*
            var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == oldRES.ReservationRoomId)
                   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
            var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == oldRES.ReservationRoomId).FirstOrDefault().RoomId;
            var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
            var room_resno = "";
            if (roomId != null)
            {
                room_resno = res.languageKeys["ROOM"] != null ? res.languageKeys["ROOM"].ToString() : "";
            }
            else
            {
                room_resno = res.languageKeys["RES_NO"] != null ? res.languageKeys["RES_NO"].ToString() : "";
            }

            extraserviceMessage = extraserviceMessage.Replace("[USER]", user.FullName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM]", roomName);
            extraserviceMessage = extraserviceMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
            extraserviceMessage = extraserviceMessage + " : " + serviceItemList;

            Notification.sendNotificationToDevice(user.UserName.ToLower(), extraserviceMessage, user.HotelId, "NOTIFICATION_WHEN_DELETE_EXTRASERVICE");
            */
            Notification.processNotificationDeleteExtraService(res, user, oldRES);
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ChangeStatus")]
        public async Task<IHttpActionResult> ChangeStatus(int RRID, string status)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == RRID).FirstOrDefault();
            if (oldRR != null)
            {
                switch (oldRR.BookingStatus)
                {
                    case "CHECKIN":
                        var conflictCheckIn = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == oldRR.ReservationRoomId && r.BookingStatus == "CHECKIN").FirstOrDefault();
                        if (conflictCheckIn != null)
                        {
                            return BadRequest("ROOM_ALREADY_HAS_A_CHECK_IN_RESERVATION_WITH_THE_SAME_ID");
                        }
                        break;

                    case "BOOKED":
                        if (status == "CHECKIN")
                        {
                            var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != oldRR.ReservationRoomId && r.RoomId == oldRR.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN") || (r.ArrivalDate < oldRR.DepartureDate && DateTime.UtcNow <= r.DepartureDate))).FirstOrDefault();
                            if (conflictReservation != null)
                            {
                                ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                                return Content(HttpStatusCode.BadRequest, conflictReservation);
                            }

                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == oldRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }

                            //var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == oldRR.RoomId).FirstOrDefault();

                            oldRR.ArrivalDate = DateTime.UtcNow;
                            if (oldRR.DepartureDate <= oldRR.ArrivalDate)
                            {
                                oldRR.DepartureDate = ((DateTime)oldRR.ArrivalDate).AddDays(1);
                            }

                            // Update Houstatus = AVAILABLE if Room is DIRTY

                            var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == oldRR.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                            if (rooms != null) rooms.HouseStatus = null;

                            oldRR.BookingStatus = status;
                            oldRR.CheckInDate = DateTime.UtcNow;
                            oldRR.CheckInUserId = user.UserId;

                            // Rebuild RoomBreakfast and Room Charges
                            var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                            ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, user, context);
                            ReservationUtility.RebuildRoomCharges(dateRange, oldRR, user, context);

                            // Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == oldRR.RoomId).FirstOrDefault().RoomName, user.HotelId, "NOTIFICATION_CHECKEDIN");
                            Notification.processNotificationCheckin(user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == oldRR.RoomId).FirstOrDefault().RoomName);
                            Utilities.AddLog("RESERVATION_CHECKIN", oldRR.ReservationRoomId.ToString(), "ROOM:" + oldRR.RoomId);

                            context.SubmitChanges();
                            
                            // Consider only if hotel is using module "Channel Mananger"
                            // Room Available
                            ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

                            //Send sms to guest
                            SMSMobifone.sendSMSNotificationCheckin(oldRR);
                        }
                        if (status == "CANCELLED")
                        {
                            oldRR.BookingStatus = "CANCELLED";
                            oldRR.CancelDate = DateTime.UtcNow;
                            oldRR.CancelUserId = user.UserId;
                            Utilities.AddLog("RESERVATION_CANCEL", oldRR.ReservationRoomId.ToString(), "ROOM:" + oldRR.RoomId);


                            context.SubmitChanges();
                            Common.Elastic.IndexLastAudit(context);
                            // Consider only if hotel is using module "Channel Mananger"
                            // Room Available
                            ReservationUtility.RebuildAvailableRoom(oldRR, user, context);
                        }
                        else
                        {
                            BadRequest("NOT_VALID_OPERATION");
                        }
                        break;

                    case "CANCELLED":
                        if (status == "AVAILABLE")
                        {
                            oldRR.BookingStatus = status;
                            context.SubmitChanges();
                            Common.Elastic.IndexLastAudit(context);
                        }
                        break;

                    default:
                        break;
                }
            }
            Elastic.IndexReservationRoom(RRID);
            Common.MemoryCacher.ClearStatusCache(user.HotelId);
            Common.Elastic.IndexLastAudit(context);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessCancel")]
        public async Task<IHttpActionResult> ProcessCancel(CancelModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            decimal totalCancelFee = 0.0M;
             
            var oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            
            if (oldRR != null)
            {
                //If refund, money is default 
                var defaultMoneyId = oldRR.Hotels.DefaultMoneyId;

                List <Payments> deletedDeposit = context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == oldRR.ReservationRoomId && p.PaymentTypeName == "DELETED" && p.RefPaymentId != null).ToList();
                List<Payments> refDeletedDeposit = new List<Payments>();
                foreach (var item in deletedDeposit)
                {
                    refDeletedDeposit.Add(context.Payments.Where(p => p.PaymentId == item.RefPaymentId).FirstOrDefault());
                }

                var allPayment = context.Payments.Where(ap => ap.HotelId == user.HotelId && ap.ReservationRoomId == oldRR.ReservationRoomId).ToList();
                var lastDepositList = allPayment.Except(deletedDeposit).Except(refDeletedDeposit).Where(ld => ld.PaymentTypeName == "DEPOSIT").ToList();
                var lastDeposit = lastDepositList.OrderByDescending(ld => ld.CreatedDate).FirstOrDefault();

                if (oldRR.BookingStatus == "CANCELLED")
                {
                    return BadRequest("RESERVATION_IS_ALREADY_CANCELLED");
                }

                if (model.CancelFlat > 0)
                {
                    totalCancelFee = totalCancelFee + model.CancelFlat;
                }
                if (model.CancelPercentage > 0)
                {
                    totalCancelFee = totalCancelFee + (decimal)model.CancelPercentage * model.TotalDeposit / 100;
                }

                if (!model.ApplyCancellationFees)
                {
                    if (model.TotalDeposit > 0)
                    {
                        var paymentDescription = model.languageKeys["REFUND_ALL_DEPOSITS_OF_RESERVATION"].ToString() + " " + oldRR.Reservations.ReservationNumber + " (" + model.TotalDeposit + ") ";
                        Payments cancelRefundPayment = new Payments();
                        cancelRefundPayment.HotelId = user.HotelId;
                        cancelRefundPayment.PaymentDescription = paymentDescription;
                        cancelRefundPayment.ReservationRoomId = model.ReservationRoomId;
                        cancelRefundPayment.PaymentTypeName = "REFUND";
                        if (lastDeposit != null)
                        {
                            cancelRefundPayment.PaymentMethodId = lastDeposit.PaymentMethodId;
                            //cancelRefundPayment.MoneyId = lastDeposit.MoneyId;
                            cancelRefundPayment.MoneyId = defaultMoneyId;
                        }

                        cancelRefundPayment.Amount = -model.TotalDeposit;
                        cancelRefundPayment.CreatedDate = DateTime.UtcNow;
                        cancelRefundPayment.CreatedUserId = user.UserId;
                        cancelRefundPayment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "REFUND");
                        context.Payments.InsertOnSubmit(cancelRefundPayment);

                        var paymentMessage = "";

                        paymentMessage = model.languageKeys["NOTIFICATION_REFUND"] != null ? model.languageKeys["NOTIFICATION_REFUND"].ToString() : "";
                        var money = "";
                        var paymethodname = "";
                        var Reppaymethodname = "";
                        if (lastDeposit != null)
                        {
                            //money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == lastDeposit.MoneyId).FirstOrDefault().MoneyName;
                            money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
                            paymethodname = context.PaymentMethods.Where(m => m.PaymentMethodId == lastDeposit.PaymentMethodId).FirstOrDefault().PaymentMethodName;
                            Reppaymethodname = model.languageKeys != null ? model.languageKeys[paymethodname].ToString() : "";
                        }
                        var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId)
                        .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                        var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().RoomId;
                        var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                        var room_resno = "";
                        if (roomId != null)
                        {
                            room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                        }
                        else
                        {
                            room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                        }

                        var spaymentAmount = Math.Abs(Convert.ToDecimal(cancelRefundPayment.Amount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));

                        paymentMessage = paymentMessage.Replace("[USER]", user.FullName);
                        paymentMessage = paymentMessage.ToString().Replace("[PAYMENTMETHOD]", Reppaymethodname);
                        paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " + spaymentAmount);
                        paymentMessage = paymentMessage.ToString().Replace("[ROOM]", roomName);
                        paymentMessage = paymentMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                        Notification.sendNotificationToDevice(user.UserName.ToLower(), paymentMessage, user.HotelId, "NOTIFICATION_WHEN_POST_PAYMENT");

                    }
                }
                else
                {
                    if (totalCancelFee > 0)
                    {
                        RoomExtraServices cancelFeeExtraService = new RoomExtraServices();
                        cancelFeeExtraService.RoomExtraServiceName = "EXTRA_SERVICES";
                        cancelFeeExtraService.RoomExtraServiceDescription = model.languageKeys["CANCEL_FEE"].ToString();
                        cancelFeeExtraService.HotelId = user.HotelId;
                        cancelFeeExtraService.ReservationRoomId = model.ReservationRoomId;
                        cancelFeeExtraService.Quantity = 1;
                        cancelFeeExtraService.Amount = totalCancelFee;
                        cancelFeeExtraService.CreatedUserId = user.UserId;
                        cancelFeeExtraService.CreatedDate = DateTime.UtcNow;
                        cancelFeeExtraService.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "EXTRA_SERVICES");
                        context.RoomExtraServices.InsertOnSubmit(cancelFeeExtraService);

                        Payments cancelFeePayment = new Payments();
                        cancelFeePayment.HotelId = user.HotelId;
                        cancelFeePayment.ReservationRoomId = model.ReservationRoomId;
                        var paymentDescription = model.languageKeys["PAYMENT_FOR_CANCELLATION_OF_RESERVATION"].ToString() + " " + oldRR.Reservations.ReservationNumber + " (";
                        if (model.CancelPercentage > 0)
                        {
                            paymentDescription = paymentDescription + model.CancelPercentage + "%";
                        }
                        if (model.CancelFlat > 0)
                        {
                            if (model.CancelPercentage > 0)
                            {
                                paymentDescription = paymentDescription + " + ";
                            }
                            paymentDescription = paymentDescription + model.CancelFlat;
                        }
                        paymentDescription = paymentDescription + ")";
                        cancelFeePayment.PaymentDescription = paymentDescription;
                        cancelFeePayment.PaymentTypeName = "NEW_PAYMENT";
                        if (lastDeposit != null)
                        {
                            cancelFeePayment.PaymentMethodId = lastDeposit.PaymentMethodId;
                            //cancelFeePayment.MoneyId = lastDeposit.MoneyId;
                            cancelFeePayment.MoneyId = defaultMoneyId;
                        }
                        cancelFeePayment.Amount = totalCancelFee;
                        cancelFeePayment.CreatedDate = DateTime.UtcNow;
                        cancelFeePayment.CreatedUserId = user.UserId;
                        cancelFeePayment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "NEW_PAYMENT");
                        context.Payments.InsertOnSubmit(cancelFeePayment);

                        var paymentMessage = "";
                        var refundMessage = "";

                        paymentMessage = model.languageKeys["NOTIFICATION_NEWPAYMENT"] != null ? model.languageKeys["NOTIFICATION_NEWPAYMENT"].ToString() : "";
                        refundMessage = model.languageKeys["NOTIFICATION_REFUND"] != null ? model.languageKeys["NOTIFICATION_REFUND"].ToString() : "";
                        var money = "";
                        var paymethodname = "";
                        if (lastDeposit != null)
                        {
                            //money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == lastDeposit.MoneyId).FirstOrDefault().MoneyName;
                            money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
                            paymethodname = context.PaymentMethods.Where(m => m.PaymentMethodId == lastDeposit.PaymentMethodId).FirstOrDefault().PaymentMethodName;
                        }
                        var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId)
                        .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                        var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().RoomId;
                        var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                        var room_resno = "";
                        if (roomId != null)
                        {
                            room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                        }
                        else
                        {
                            room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                        }

                        var spaymentAmount = Math.Abs(Convert.ToDecimal(cancelFeePayment.Amount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));

                        paymentMessage = paymentMessage.Replace("[USER]", user.FullName);
                        paymentMessage = paymentMessage.ToString().Replace("[PAYMENTMETHOD]", model.languageKeys != null ? model.languageKeys[paymethodname].ToString() : "");
                        // paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " + Math.Abs(Convert.ToDecimal(cancelFeePayment.Amount)).ToString("0,0", CultureInfo.InvariantCulture));
                        paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " + spaymentAmount);
                        paymentMessage = paymentMessage.ToString().Replace("[ROOM]", roomName);
                        paymentMessage = paymentMessage.ToString().Replace("[ROOM_RESNO]", room_resno);

                        spaymentAmount = Math.Abs(Convert.ToDecimal(model.TotalDeposit)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));

                        refundMessage = refundMessage.Replace("[USER]", user.FullName);
                        refundMessage = refundMessage.ToString().Replace("[PAYMENTMETHOD]", model.languageKeys != null ? model.languageKeys[paymethodname].ToString() : "");
                        //refundMessage = refundMessage.ToString().Replace("[MONEY]", money + " " + Math.Abs(Convert.ToDecimal(model.TotalDeposit)).ToString("0,0", CultureInfo.InvariantCulture));
                        refundMessage = refundMessage.ToString().Replace("[MONEY]", money + " " + spaymentAmount);
                        refundMessage = refundMessage.ToString().Replace("[ROOM]", roomName);
                        refundMessage = refundMessage.ToString().Replace("[ROOM_RESNO]", room_resno);

                        Notification.sendNotificationToDevice(user.UserName.ToLower(), paymentMessage, user.HotelId, "NOTIFICATION_WHEN_POST_PAYMENT");
                        
                        Payments cancelRefundPayment = new Payments();
                        cancelRefundPayment.HotelId = user.HotelId;
                        cancelRefundPayment.ReservationRoomId = model.ReservationRoomId;
                        cancelRefundPayment.PaymentTypeName = "REFUND";
                        if (lastDeposit != null)
                        {
                            cancelRefundPayment.PaymentMethodId = lastDeposit.PaymentMethodId;
                            //cancelRefundPayment.MoneyId = lastDeposit.MoneyId;
                            cancelRefundPayment.MoneyId = defaultMoneyId;
                        }
                        cancelRefundPayment.Amount = -model.TotalDeposit;
                        cancelRefundPayment.CreatedDate = DateTime.UtcNow;
                        cancelRefundPayment.CreatedUserId = user.UserId;
                        cancelRefundPayment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "REFUND");
                        context.Payments.InsertOnSubmit(cancelRefundPayment);
                    }
                }
                oldRR.BookingStatus = "CANCELLED";
                oldRR.CancelReason = model.CancelReason;
                oldRR.CancelDate = DateTime.UtcNow;
                oldRR.CancelUserId = user.UserId;  

                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                var tmpReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.ReservationRoomId)
                        .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                var roomId2 = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().RoomId;
                if (roomId2 != null)
                {
                    var customer_name = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().Travellers.Fullname;
                    var roomName2 = roomId2 != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId2).FirstOrDefault().RoomName : tmpReservationNumber.ToString();
                    Notification.processNotificationCanceled(user, tmpReservationNumber, roomName2, customer_name, model.CancelReason, model.languageKeys["NOTIFICATION_CANCELED_CONTENT"].ToString());
                }else
                {
                    var customer_name = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().Travellers.Fullname;
                    Notification.processNotificationCanceledNan(user, tmpReservationNumber,  customer_name, model.CancelReason, model.languageKeys["NOTIFICATION_CANCELED_NAN_CONTENT"].ToString());
                }
                // Consider only if hotel is using module "Channel Mananger"
                // Room Available
                ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

            }
            return Ok();
        }

        public class ProcessUndoCancelReservationModel
        {
            public int RRID { get; set; } 
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessUndoCancelReservation")]
        public async Task<IHttpActionResult> ProcessUndoCancelReservation(ProcessUndoCancelReservationModel model)
        {
            int RRID = model.RRID;
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == RRID).FirstOrDefault();
            if (oldRR != null)
            {
                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == oldRR.RoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && (r.ArrivalDate < oldRR.DepartureDate && oldRR.ArrivalDate <= r.DepartureDate)).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == oldRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_UNDO_CANCEL_TO_REPAIRING_TIME");
                }
                var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == oldRR.RoomId).FirstOrDefault();
                if (currentRoom != null && currentRoom.HouseStatus == "REPAIR")
                {
                    if (currentRoom.RepairStartDate == null)
                    {
                        currentRoom.RepairStartDate = ((DateTime)SqlDateTime.MinValue);
                    }
                    if (currentRoom.RepairEndDate == null)
                    {
                        currentRoom.RepairEndDate = ((DateTime)SqlDateTime.MaxValue);
                    }
                    if (currentRoom.RepairStartDate < oldRR.DepartureDate && oldRR.ArrivalDate <= currentRoom.RepairEndDate)
                    {
                        return BadRequest("CAN_NOT_PROCESS_REPAIRING_ROOM");
                    }
                }
                oldRR.BookingStatus = "BOOKED";
                



                context.SubmitChanges();
                

                // Consider only if hotel is using module "Channel Mananger"

                
                if (currentRoom!= null)
                {
                    //var customer_name = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == model.ReservationRoomId).FirstOrDefault().Travellers.Fullname;
                    //var roomName2 = roomId2 != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId2).FirstOrDefault().RoomName : tmpReservationNumber.ToString(); 
                    Notification.processNotificationUndoCancel(user, (int)oldRR.Reservations.ReservationNumber, oldRR.Rooms.RoomName, oldRR.Travellers.Fullname, model.languageKeys["NOTIFICATION_UNDO_CANCEL_CONTENT"].ToString());
                }
                else
                {
                    Notification.processNotificationUndoCancelNan(user, (int) oldRR.Reservations.ReservationNumber,  oldRR.Travellers.Fullname, model.languageKeys["NOTIFICATION_UNDO_CANCEL_NAN_CONTENT"].ToString());
                }
                // Room Available
                ReservationUtility.RebuildAvailableRoom(oldRR, user, context);
                Common.Elastic.IndexLastAudit(context);
            }
            Elastic.IndexReservationRoom(RRID); 
            Common.MemoryCacher.ClearStatusCache(user.HotelId);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessCheckIn")]
        public async Task<IHttpActionResult> ProcessCheckIn(int RRID, int roomPriceId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == RRID).FirstOrDefault();
            if (oldRR != null)
            {
                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == oldRR.RoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && (r.BookingStatus == "CHECKIN" || (r.ArrivalDate < oldRR.DepartureDate && DateTime.Now <= r.DepartureDate))).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    return Content(HttpStatusCode.BadRequest, conflictReservation);
                }
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == oldRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                    return BadRequest("CAN_NOT_CHECK_IN_TO_REPAIRING_TIME");
                }
                oldRR.ArrivalDate = DateTime.UtcNow;
                if (oldRR.DepartureDate <= oldRR.ArrivalDate)
                {
                    oldRR.DepartureDate = ((DateTime)oldRR.ArrivalDate).AddDays(1);
                }
                oldRR.BookingStatus = "CHECKIN";
                if (oldRR.RoomPriceId == null)
                {
                    oldRR.RoomPriceId = roomPriceId;
                }
                oldRR.CheckInDate = DateTime.UtcNow;
                oldRR.CheckInUserId = user.UserId;

                // Update Houstatus = AVAILABLE if Room is DIRTY

                var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == oldRR.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                if (rooms != null)
                {
                    rooms.HouseStatus = null;
                }
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);

                // Consider only if hotel is using module "Channel Mananger"
                // Room Available
                ReservationUtility.RebuildAvailableRoom(oldRR, user, context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAssignRate")]
        public async Task<IHttpActionResult> ProcessAssignRate(int RRID, int roomPriceId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var oldRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == RRID).FirstOrDefault();
            if (oldRR != null)
            {
                if (oldRR.RoomPriceId == null)
                {
                    oldRR.RoomPriceId = roomPriceId;
                }
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ChangeRoomStatus")]
        public async Task<IHttpActionResult> ChangeRoomStatus(int roomId, string status)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            Rooms room = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault();
            switch (room.HouseStatus)
            {
                case "DIRTY":
                    if (status == "CLEAN")
                    {
                        room.HouseStatus = null;
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                    }
                    break;
            }
            return Ok(room.HouseStatus);
        }
        

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditPrice")]
        public async Task<IHttpActionResult> EditPrice(EditPriceModel model)
        {
            //var editPriceMessage = "";
            //editPriceMessage = model.languageKeys["NOTIFICATION_WHEN_CHANGE_PRICE"] != null ? model.languageKeys["NOTIFICATION_WHEN_CHANGE_PRICE"].ToString() : "";

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            ReservationRooms currentRR = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            if (currentRR != null)
            {
                //var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == currentRR.ReservationRoomId)
                //   .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                //var roomId = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId == currentRR.ReservationRoomId).FirstOrDefault().RoomId;
                //var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                //var room_resno = "";
                //if (roomId != null)
                //{
                //    room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                //}
                //else
                //{
                //    room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                //}

                //var defaultMoneyId = context.Hotels.Where(h => h.HotelId == currentClientUser.HotelId).FirstOrDefault().DefaultMoneyId;
                //var money = context.Money.Where(m => m.HotelId == currentClientUser.HotelId && m.MoneyId == defaultMoneyId).FirstOrDefault().MoneyName;
                //if (money == null) money = "VND";

                //editPriceMessage = editPriceMessage.Replace("[USER]", currentClientUser.FullName);
                //editPriceMessage = editPriceMessage.ToString().Replace("[ROOM]", roomName);
                //editPriceMessage = editPriceMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                //var spaymentAmount = Math.Abs(Convert.ToDecimal(currentRR.Price)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                //editPriceMessage = editPriceMessage.ToString().Replace("[OLD_PRICE]", spaymentAmount);

                ////editPriceMessage = editPriceMessage.ToString().Replace("[OLD_PRICE]", Math.Abs(Convert.ToDecimal(currentRR.Price)).ToString("0,0", CultureInfo.InvariantCulture));
                ////editPriceMessage = editPriceMessage.ToString().Replace("[NEW_PRICE]", Math.Abs(Convert.ToDecimal(model.NewPrice)).ToString("0,0", CultureInfo.InvariantCulture));
                //spaymentAmount = Math.Abs(Convert.ToDecimal(model.NewPrice)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                //editPriceMessage = editPriceMessage.ToString().Replace("[NEW_PRICE]", money + " " + spaymentAmount);

                //Notification.sendNotificationToDevice(currentClientUser.UserName.ToLower(), editPriceMessage, currentClientUser.HotelId, "NOTIFICATION_CHANGE_PRICE");

                Notification.processNotificationEditPrice(model, currentClientUser, currentRR);
                currentRR.Price = model.NewPrice;

                //Delete old RoomCharge to reset new RoomCharge 
                context.ExecuteCommand("Delete RoomCharges where HotelId={0} and ReservationRoomId={1}", currentRR.HotelId, currentRR.ReservationRoomId);
                context.SubmitChanges();

                var dateRange = new DateRange(currentRR.ArrivalDate.Value, currentRR.DepartureDate.Value);
                ReservationUtility.RebuildRoomBreakfasts(dateRange, currentRR, currentClientUser, context);
                ReservationUtility.RebuildRoomCharges(dateRange, currentRR, currentClientUser, context);

                Common.Elastic.IndexLastAudit(context);
            }
            else
            {
                return BadRequest("RESERVATION_DOES_NOT_EXIST");
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditNote")]
        public async Task<IHttpActionResult> EditNote(EditNoteModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            ReservationRooms currentRR = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == model.ReservationRoomId).FirstOrDefault();
            if (currentRR != null)
            {
                currentRR.Note = model.NewNote;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            else
            {
                return BadRequest("RESERVATION_DOES_NOT_EXIST");
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddRoomRemark")]
        public async Task<IHttpActionResult> AddRoomRemark(RoomRemarkModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();

            RoomRemarks roomRemarkAdded = new RoomRemarks();
            roomRemarkAdded.HotelId = currentClientUser.HotelId;
            roomRemarkAdded.ReservationRoomId = model.ReservationRoomId;
            roomRemarkAdded.RemarkEventId = model.RemarkEventId;
            roomRemarkAdded.Description = model.Description;
            roomRemarkAdded.IsCompleted = false;
            roomRemarkAdded.IsDeleted = false;
            roomRemarkAdded.CreatedDate = DateTime.UtcNow;
            roomRemarkAdded.CreatedUserId = currentClientUser.UserId;
            context.RoomRemarks.InsertOnSubmit(roomRemarkAdded);
            context.SubmitChanges();

            Common.Elastic.IndexLastAudit(context);

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditRoomRemark")]
        public async Task<IHttpActionResult> EditRoomRemark(RoomRemarkModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var currentRoomRemark = context.RoomRemarks.Where(rrm => rrm.HotelId == currentClientUser.HotelId && rrm.RoomRemarkId == model.RoomRemarkId).FirstOrDefault();
            if (currentRoomRemark != null)
            {
                currentRoomRemark.RemarkEventId = model.RemarkEventId;
                currentRoomRemark.Description = model.Description;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetRoomRemarks")]
        public async Task<IHttpActionResult> GetRoomRemarks(int RRID)
        {
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            return Ok(context.RoomRemarks.Where(rm => rm.HotelId == currentClientUser.HotelId && rm.ReservationRoomId == RRID).ToList());
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RemoveRoomRemark")]
        public async Task<IHttpActionResult> RemoveRoomRemark(RoomRemarkModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            RoomRemarks roomRemark = context.RoomRemarks.Where(rrm => rrm.HotelId == currentClientUser.HotelId && rrm.RoomRemarkId == model.RoomRemarkId).FirstOrDefault();
            if (roomRemark != null)
            {
                roomRemark.IsDeleted = true;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }

            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ChangeRoomRemarkStatus")]
        public async Task<IHttpActionResult> ChangeRoomRemarkStatus(RoomRemarkModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            RoomRemarks roomRemark = context.RoomRemarks.Where(rrm => rrm.HotelId == currentClientUser.HotelId && rrm.RoomRemarkId == model.RoomRemarkId).FirstOrDefault();
            if (roomRemark != null)
            {
                roomRemark.IsCompleted = model.IsCompleted;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        public class ChangeReservationStatusModel
        {
            public int RRID { get; set; }
            public string Reason { get; set; }
            public string ActionCode { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessChangeReservationStatus")]
        public async Task<IHttpActionResult> ProcessChangeReservationStatus(ChangeReservationStatusModel model)
        {
            //var preMessage = "";
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentRR = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.RRID).FirstOrDefault();
            if (currentRR != null)
            {
                if (model.ActionCode == "PRE_CHECKIN")
                {
                    //preMessage = model.languageKeys["NOTIFICATION_PRE_CHẸCKIN"] != null ? model.languageKeys["NOTIFICATION_PRE_CHẸCKIN"].ToString() : "";
                    if (currentRR.BookingStatus != "CHECKIN")
                    {
                        return BadRequest("CANNOT_PROCESS_PRE_CHECKIN");
                    }
                    var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != currentRR.ReservationRoomId && r.RoomId == currentRR.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && currentRR.BookingStatus == "CHECKIN") || (r.ArrivalDate < currentRR.DepartureDate && currentRR.ArrivalDate <= r.DepartureDate))).FirstOrDefault();
                    if (conflictReservation != null)
                    {
                        ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                        return Content(HttpStatusCode.BadRequest, conflictReservation);
                    }

                    var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == currentRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= currentRR.DepartureDate && currentRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                    if (conflictRoomRepair != null)
                    {
                        return BadRequest("CAN_NOT_PRE_CHECK_IN_TO_REPAIRING_TIME");
                    }

                    var roomExtraServices = context.RoomExtraServices.Where(rmES => rmES.HotelId == user.HotelId && rmES.ReservationRoomId == model.RRID).ToList();
                    if (roomExtraServices != null && roomExtraServices.Count() > 0)
                    {
                        for (int i = 0; i < roomExtraServices.Count(); i++)
                        {
                            if (roomExtraServices[i].CreatedDate >= currentRR.CheckInDate && !roomExtraServices[i].IsDeleted)
                            {
                                roomExtraServices[i].IsDeleted = true;
                                roomExtraServices[i].DeletedDate = DateTime.UtcNow;
                                roomExtraServices[i].DeletedReason = model.languageKeys["THIS_ROOM_EXTRA_SERVICE_WAS_DELETED_AUTOMATICALLY_BY_THE_PRE_CHECKIN_PROCESS"].ToString();
                                roomExtraServices[i].DeletedBy = user.UserId;
                            }
                        }
                    }

                    var roomExtraServiceItems = context.RoomExtraServiceItems.Where(rmESI => rmESI.HotelId == user.HotelId && rmESI.ReservationRoomId == model.RRID).ToList();
                    if (roomExtraServiceItems != null && roomExtraServiceItems.Count() > 0)
                    {
                        for (int i = 0; i < roomExtraServiceItems.Count(); i++)
                        {
                            var roomExtraService = roomExtraServices.Where(res => res.RoomExtraServiceId == roomExtraServiceItems[i].RoomExtraServiceId).FirstOrDefault();
                            if (roomExtraService.CreatedDate >= currentRR.CheckInDate && !roomExtraServiceItems[i].IsDeleted)
                            {
                                roomExtraServiceItems[i].IsDeleted = true;
                                roomExtraServiceItems[i].DeletedDate = DateTime.UtcNow;
                                roomExtraServiceItems[i].DeletedReason = model.languageKeys["THIS_ROOM_EXTRA_SERVICE_ITEM_WAS_DELETED_AUTOMATICALLY_BY_THE_PRE_CHECKIN_PROCESS"].ToString();
                                roomExtraServiceItems[i].DeletedBy = user.UserId;
                            }
                        }
                    }

                    var payments = context.Payments.Where(pm => pm.HotelId == user.HotelId && pm.ReservationRoomId == model.RRID).ToList();
                    if (payments != null && payments.Count() > 0)
                    {
                        for (int i = 0; i < payments.Count(); i++)
                        {
                            if (payments[i].CreatedDate >= currentRR.CheckInDate && payments[i].RefPaymentId == null)
                            {
                                Payments paymentTemp = new Payments();
                                paymentTemp.PaymentDescription = model.languageKeys["THIS_PAYMENT_WAS_DELETED_AUTOMATICALLY_BY_THE_PRE_CHECKIN_PROCESS"].ToString();
                                paymentTemp.HotelId = user.HotelId;
                                paymentTemp.ReservationRoomId = currentRR.ReservationRoomId;
                                paymentTemp.PaymentTypeName = "DELETED";
                                paymentTemp.Amount = -payments[i].Amount;
                                paymentTemp.CreatedDate = DateTime.UtcNow;
                                paymentTemp.CreatedUserId = user.UserId;
                                paymentTemp.PaymentMethodId = payments[i].PaymentMethodId;
                                paymentTemp.MoneyId = payments[i].MoneyId;
                                paymentTemp.RefPaymentId = payments[i].PaymentId;
                                paymentTemp.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "PAYMENT");
                                context.Payments.InsertOnSubmit(paymentTemp);
                                context.SubmitChanges();
                                payments[i].RefPaymentId = paymentTemp.PaymentId;
                                context.SubmitChanges();
                            }
                        }
                    }
                    currentRR.BookingStatus = "BOOKED";
                    ChangeReservationStatus changeStatus = new ChangeReservationStatus();
                    changeStatus.HotelId = user.HotelId;
                    changeStatus.ReservationRoomId = currentRR.ReservationRoomId;
                    changeStatus.CreatedDate = DateTime.UtcNow;
                    changeStatus.CreatedUserId = user.UserId;
                    changeStatus.Reason = model.Reason;
                    changeStatus.ActionCode = model.ActionCode;
                    changeStatus.ActionPoint = currentRR.CheckInDate;
                    context.ChangeReservationStatus.InsertOnSubmit(changeStatus);
                    /*
                    var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == currentRR.ReservationRoomId)
                    .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                    var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == currentRR.ReservationRoomId).FirstOrDefault().RoomId;
                    var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                    var room_resno = "";
                    if (roomId != null)
                    {
                        room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                    }
                    else
                    {
                        room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                    }

                    preMessage = preMessage.Replace("[USER]", user.FullName);
                    preMessage = preMessage.ToString().Replace("[ROOM]", roomName);
                    preMessage = preMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                    Notification.sendNotificationToDevice(user.UserName.ToLower(), preMessage, user.HotelId, "NOTIFICATION_WHEN_PRE_CHECKIN");
                    */
                    Notification.processNotificationPreCheckin(model, user, currentRR);
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                }

                if (model.ActionCode == "PRE_CHECKOUT")
                {
                    //preMessage = model.languageKeys["NOTIFICATION_PRE_CHẸCKOUT"] != null ? model.languageKeys["NOTIFICATION_PRE_CHẸCKOUT"].ToString() : "";
                    var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != currentRR.ReservationRoomId && r.RoomId == currentRR.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && currentRR.BookingStatus == "CHECKIN") || (r.BookingStatus == "BOOKED" && currentRR.BookingStatus == "CHECKIN") || (r.ArrivalDate < currentRR.DepartureDate && currentRR.ArrivalDate <= r.DepartureDate))).FirstOrDefault();
                    if (conflictReservation != null)
                    {
                        ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                        return Content(HttpStatusCode.BadRequest, conflictReservation);
                    }
                    var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == currentRR.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= currentRR.DepartureDate && currentRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                    if (conflictRoomRepair != null)
                    {
                        return BadRequest("CAN_NOT_PRE_CHECK_OUT_TO_REPAIRING_TIME");
                    }
                    currentRR.BookingStatus = "CHECKIN";
                    ChangeReservationStatus changeStatus = new ChangeReservationStatus();
                    changeStatus.HotelId = user.HotelId;
                    changeStatus.ReservationRoomId = currentRR.ReservationRoomId;
                    changeStatus.CreatedDate = DateTime.UtcNow;
                    changeStatus.CreatedUserId = user.UserId;
                    changeStatus.Reason = model.Reason;
                    changeStatus.ActionCode = model.ActionCode;
                    changeStatus.ActionPoint = currentRR.CheckOutDate;
                    context.ChangeReservationStatus.InsertOnSubmit(changeStatus);
                    /*
                    var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == currentRR.ReservationRoomId)
                    .Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                    var roomId = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == currentRR.ReservationRoomId).FirstOrDefault().RoomId;
                    var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                    var room_resno = "";
                    if (roomId != null)
                    {
                        room_resno = model.languageKeys["ROOM"] != null ? model.languageKeys["ROOM"].ToString() : "";
                    }
                    else
                    {
                        room_resno = model.languageKeys["RES_NO"] != null ? model.languageKeys["RES_NO"].ToString() : "";
                    }

                    preMessage = preMessage.Replace("[USER]", user.FullName);
                    preMessage = preMessage.ToString().Replace("[ROOM]", roomName);
                    preMessage = preMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                    Notification.sendNotificationToDevice(user.UserName.ToLower(), preMessage, user.HotelId, "NOTIFICATION_WHEN_PRE_CHECKOUT");
                    */
                    Notification.processNotificationPreCheckout(model, user, currentRR);

                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);

                    // Consider only if hotel is using module "Channel Mananger"
                    // Room Available
                    ReservationUtility.RebuildAvailableRoom(currentRR, user, context);
                }
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CreateRoomInvoice")]
        public async Task<IHttpActionResult> CreateRoomInvoice(CalculateRoomPrice model)
        {
            //if (!ModelState.IsValid)
            //{
            //    return BadRequest(ModelState);
            //}
            
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == currentClientUser.HotelId).FirstOrDefault();
            //var currentReservation = currentHotel.ReservationRoomsList.Where(rr => rr.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
            var currentReservation = context.ReservationRooms.Where(rr => rr.ReservationRoomId == model.reservationRoomId && rr.HotelId == currentHotel.HotelId).FirstOrDefault();
            model.roomTypeId = (int)currentReservation.RoomTypeId;
            if ((currentReservation.BookingStatus != "CHECKOUT" && currentReservation.BookingStatus != "CANCELLED"))
            {
                var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(model);

                // Delete Old Items
                List<ReportItems> oldItems = currentReservation.ReportItemsList.Where(rpi => rpi.ReservationRoomId == model.reservationRoomId).ToList();
                context.ReportItems.DeleteAllOnSubmit(oldItems);

                // Create Report Items
                if (planListDateRange.planListConstantlyFormula.Count > 0)
                {
                    foreach (var formula in planListDateRange.planListConstantlyFormula)
                    {
                        ReportItems item = new ReportItems();
                        string nameTemp = "";
                        if (formula.Name == "MONTHLY_PRICE")
                        {
                            nameTemp = model.languageKeys["ROOM_MONTHLY"].ToString();
                        }
                        if (formula.Name == "WEEKLY_PRICE")
                        {
                            nameTemp = model.languageKeys["ROOM_WEEKLY"].ToString();
                        }
                        item.ReservationRoomId = model.reservationRoomId;
                        item.ItemName = nameTemp + "(" + formula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + formula.Range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                        item.ItemDescription = nameTemp + "(" + formula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + formula.Range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                        item.ItemDate = formula.Range.Start.Date.AddHours(currentHotel.TimeZoneOffset / 60);
                        item.ItemQuantity = formula.FormulaPeriod;
                        item.ItemPrice = formula.FormulaValue;
                        item.ItemTotal = formula.ValueAfter - formula.ValueBefore;
                        item.ItemType = "ROOM_PRICE_CONSTANTLY";
                        context.ReportItems.InsertOnSubmit(item);
                    }
                }

                if (planListDateRange.planListFullDayFormula.Count > 0)
                {
                    int count = planListDateRange.planListFullDayFormula.Count;

                    if (currentReservation.RoomPrices.UseHourlyPrice == true)
                    {
                        ReportItems item = new ReportItems();
                        item.ReservationRoomId = model.reservationRoomId;
                        item.ItemName = model.languageKeys["ROOM_FULL_DAY"].ToString() + "(" + planListDateRange.planListFullDayFormula[0].range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + planListDateRange.planListFullDayFormula[count - 1].range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                        item.ItemDescription = model.languageKeys["ROOM_FULL_DAY"].ToString() + "(" + planListDateRange.planListFullDayFormula[0].range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + planListDateRange.planListFullDayFormula[count - 1].range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                        item.ItemDate = planListDateRange.planListFullDayFormula[0].range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                        item.ItemQuantity = count;
                        item.ItemPrice = planListDateRange.planListFullDayFormula[0].formula.FormulaValue;
                        item.ItemTotal = (decimal)item.ItemQuantity * item.ItemPrice;
                        item.ItemType = "ROOM_PRICE_FULL_DAY";
                        context.ReportItems.InsertOnSubmit(item);
                    }
                    else
                    {
                        foreach (var formulaTemp in planListDateRange.planListFullDayFormula)
                        {
                            ReportItems item = new ReportItems();
                            item.ReservationRoomId = model.reservationRoomId;
                            item.ItemName = model.languageKeys["ROOM_FULL_DAY"].ToString();
                            item.ItemDescription = model.languageKeys["ROOM_FULL_DAY"].ToString();
                            item.ItemDate = formulaTemp.range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                            item.ItemQuantity = 1;
                            item.ItemPrice = formulaTemp.formula.FormulaValue;
                            item.ItemTotal = (decimal)item.ItemQuantity * item.ItemPrice;
                            item.ItemType = "ROOM_PRICE_FULL_DAY";
                            context.ReportItems.InsertOnSubmit(item);
                        }
                    }

                    if (planListDateRange.planListFullDayFormula[0].formula.FormulaEarlyCheckIn != null)
                    {
                        ReportItems itemEarlyCheckIn = new ReportItems();
                        itemEarlyCheckIn.ReservationRoomId = model.reservationRoomId;
                        itemEarlyCheckIn.ItemName = model.languageKeys["FULL_DAY_EARLY_CHECKIN"].ToString();
                        itemEarlyCheckIn.ItemDescription = model.languageKeys["FULL_DAY_EARLY_CHECKIN"].ToString();
                        itemEarlyCheckIn.ItemDate = planListDateRange.planListFullDayFormula[0].range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                        itemEarlyCheckIn.ItemQuantity = 1;
                        var earlyCheckIn = (decimal)planListDateRange.planListFullDayFormula[0].formula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                        if (earlyCheckIn != 0)
                        {
                            itemEarlyCheckIn.ItemPrice = (decimal)planListDateRange.planListFullDayFormula[0].formula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                            itemEarlyCheckIn.ItemTotal = (decimal)planListDateRange.planListFullDayFormula[0].formula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                        }
                        itemEarlyCheckIn.ItemType = "FULL_DAY_EARLY_CHECKIN";
                        context.ReportItems.InsertOnSubmit(itemEarlyCheckIn);
                    }

                    if (planListDateRange.planListFullDayFormula[count - 1].formula.FormulaLateCheckOut != null)
                    {
                        ReportItems itemLateCheckOut = new ReportItems();
                        itemLateCheckOut.ReservationRoomId = model.reservationRoomId;
                        itemLateCheckOut.ItemName = model.languageKeys["FULL_DAY_LATE_CHECKOUT"].ToString();
                        itemLateCheckOut.ItemDescription = model.languageKeys["FULL_DAY_LATE_CHECKOUT"].ToString();
                        itemLateCheckOut.ItemDate = planListDateRange.planListFullDayFormula[count - 1].range.End.AddHours(currentHotel.TimeZoneOffset / 60);
                        itemLateCheckOut.ItemQuantity = 1;
                        var lateCheckOut = (decimal)planListDateRange.planListFullDayFormula[count - 1].formula.FormulaLateCheckOut.Values.FirstOrDefault();
                        if (lateCheckOut != 0)
                        {
                            itemLateCheckOut.ItemPrice = (decimal)planListDateRange.planListFullDayFormula[count - 1].formula.FormulaLateCheckOut.Values.First();
                            itemLateCheckOut.ItemTotal = (decimal)planListDateRange.planListFullDayFormula[count - 1].formula.FormulaLateCheckOut.Values.First();
                        }

                        itemLateCheckOut.ItemType = "FULL_DAY_LATE_CHECKOUT";
                        context.ReportItems.InsertOnSubmit(itemLateCheckOut);
                    }
                }

                if (planListDateRange.planListHourlyFormula != null && planListDateRange.planListHourlyFormula.finalHourlyFormula != null)
                {
                    string nameHourlyTemp = "";
                    if (planListDateRange.planListHourlyFormula.finalHourlyFormula.Name == "FULL_DAY_PRICE")
                    {
                        nameHourlyTemp = model.languageKeys["ROOM_FULL_DAY"].ToString();
                    }
                    else if (planListDateRange.planListHourlyFormula.finalHourlyFormula.Name == "DAY_NIGHT_PRICE")
                    {
                        nameHourlyTemp = model.languageKeys["ROOM_DAY_NIGHT"].ToString();
                    }
                    else
                    {
                        nameHourlyTemp = model.languageKeys["ROOM_HOURLY"].ToString();
                    }

                    ReportItems item = new ReportItems();
                    item.ReservationRoomId = model.reservationRoomId;

                    item.ItemName = nameHourlyTemp + "(" + planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                    item.ItemDescription = nameHourlyTemp + "(" + planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + " - " + planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.End.AddHours(currentHotel.TimeZoneOffset / 60).ToString("dd/MM HH:mm") + ")";
                    item.ItemDate = planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                    item.ItemQuantity = 1;
                    item.ItemPrice = planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaValue;
                    item.ItemTotal = (decimal)item.ItemQuantity * item.ItemPrice;
                    item.ItemType = "ROOM_PRICE_HOURLY";
                    context.ReportItems.InsertOnSubmit(item);

                    if (planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaEarlyCheckIn != null)
                    {
                        string nameTemp = "";
                        if (planListDateRange.planListHourlyFormula.finalHourlyFormula.Name == "FULL_DAY_PRICE")
                        {
                            nameTemp = model.languageKeys["FULL_DAY_EARLY_CHECKIN"].ToString();
                        }
                        else
                        {
                            nameTemp = model.languageKeys["DAY_NIGHT_EARLY_CHECKIN"].ToString();
                        }

                        ReportItems itemEarlyCheckIn = new ReportItems();
                        itemEarlyCheckIn.ReservationRoomId = model.reservationRoomId;
                        itemEarlyCheckIn.ItemName = nameTemp;
                        itemEarlyCheckIn.ItemDescription = nameTemp;
                        itemEarlyCheckIn.ItemDate = planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                        itemEarlyCheckIn.ItemQuantity = 1;
                        var earlyCheckIn = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                        if (earlyCheckIn != 0)
                        {
                            itemEarlyCheckIn.ItemPrice = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                            itemEarlyCheckIn.ItemTotal = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaEarlyCheckIn.Values.FirstOrDefault();
                        }

                        itemEarlyCheckIn.ItemType = "HOURLY_EARLY_CHECKIN";
                        context.ReportItems.InsertOnSubmit(itemEarlyCheckIn);
                    }

                    if (planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaLateCheckOut != null)
                    {
                        string nameTemp = "";
                        if (planListDateRange.planListHourlyFormula.finalHourlyFormula.Name == "FULL_DAY_PRICE")
                        {
                            nameTemp = model.languageKeys["FULL_DAY_LATE_CHECKOUT"].ToString();
                        }
                        else
                        {
                            nameTemp = model.languageKeys["DAY_NIGHT_LATE_CHECKOUT"].ToString();
                        }

                        ReportItems itemLateCheckOut = new ReportItems();
                        itemLateCheckOut.ReservationRoomId = model.reservationRoomId;
                        itemLateCheckOut.ItemName = nameTemp;
                        itemLateCheckOut.ItemDescription = nameTemp;
                        itemLateCheckOut.ItemDate = planListDateRange.planListHourlyFormula.finalHourlyFormula.Range.Start.AddHours(currentHotel.TimeZoneOffset / 60);
                        itemLateCheckOut.ItemQuantity = 1;
                        var earlyCheckIn = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaLateCheckOut.Values.FirstOrDefault();
                        if (earlyCheckIn != 0)
                        {
                            itemLateCheckOut.ItemPrice = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaLateCheckOut.Values.FirstOrDefault();
                            itemLateCheckOut.ItemTotal = (decimal)planListDateRange.planListHourlyFormula.finalHourlyFormula.FormulaLateCheckOut.Values.FirstOrDefault();
                        }

                        itemLateCheckOut.ItemType = "HOURLY_EARLY_CHECKIN";
                        context.ReportItems.InsertOnSubmit(itemLateCheckOut);
                    }
                }

                if (planListDateRange.extraAdults != null)
                {
                    ReportItems item = new ReportItems();
                    item.ReservationRoomId = model.reservationRoomId;
                    item.ItemName = model.languageKeys["EXTRA_ADULTS"].ToString();
                    item.ItemDescription = model.languageKeys["EXTRA_ADULTS"].ToString();
                    item.ItemDate = null;
                    item.ItemQuantity = planListDateRange.extraAdults.Extra;
                    item.ItemPrice = planListDateRange.extraAdults.DefaultPrice;
                    item.ItemTotal = planListDateRange.extraAdults.ExtraPrice;
                    item.ItemType = "EXTRA_TRAVELLER";
                    context.ReportItems.InsertOnSubmit(item);
                }

                if (planListDateRange.extraChildren != null)
                {
                    ReportItems item = new ReportItems();
                    item.ReservationRoomId = model.reservationRoomId;
                    item.ItemName = model.languageKeys["EXTRA_CHILDREN"].ToString();
                    item.ItemDescription = model.languageKeys["EXTRA_CHILDREN"].ToString();
                    item.ItemDate = null;
                    item.ItemQuantity = planListDateRange.extraChildren.Extra;
                    item.ItemPrice = planListDateRange.extraChildren.DefaultPrice;
                    item.ItemTotal = planListDateRange.extraChildren.ExtraPrice;
                    item.ItemType = "EXTRA_TRAVELLER";
                    context.ReportItems.InsertOnSubmit(item);
                }

                List<ExtraServiceItems> extraServiceItems = context.ExtraServiceItems.Where(esi => esi.HotelId == currentClientUser.HotelId).ToList();
                List<RoomExtraServices> roomExtraServices = context.RoomExtraServices.Where(rs => rs.HotelId == currentClientUser.HotelId && rs.ReservationRoomId == model.reservationRoomId).ToList();
                if (roomExtraServices.Count > 0)
                {
                    foreach (var roomES in roomExtraServices)
                    {
                        if (roomES.RoomExtraServiceName != "EXTRA_SERVICES")
                        {
                            List<RoomExtraServiceItems> roomExtraServiceItems = context.RoomExtraServiceItems.Where(rsi => rsi.HotelId == currentClientUser.HotelId && rsi.ReservationRoomId == model.reservationRoomId && rsi.RoomExtraServiceId == roomES.RoomExtraServiceId && !rsi.IsDeleted).ToList();
                            foreach (var roomESItem in roomExtraServiceItems)
                            {
                                ReportItems item = new ReportItems();
                                item.ReservationRoomId = model.reservationRoomId;
                                item.ItemName = extraServiceItems.Where(esi => esi.ExtraServiceItemId == roomESItem.ExtraServiceItemId).FirstOrDefault().ExtraServiceItemName;
                                item.ItemDescription = extraServiceItems.Where(esi => esi.ExtraServiceItemId == roomESItem.ExtraServiceItemId).FirstOrDefault().ExtraServiceItemName;
                                DateTime dateTemp = roomES.CreatedDate ?? default(DateTime);
                                item.ItemDate = dateTemp.AddHours(currentHotel.TimeZoneOffset / 60);
                                item.ItemQuantity = roomESItem.Quantity;
                                item.ItemPrice = roomESItem.Price;
                                item.ItemTotal = roomESItem.Quantity * roomESItem.Price;
                                item.ItemType = roomES.RoomExtraServiceName;
                                context.ReportItems.InsertOnSubmit(item);
                            }
                        }
                        else
                        {
                            if (!roomES.IsDeleted)
                            {
                                ReportItems item = new ReportItems();
                                item.ReservationRoomId = model.reservationRoomId;
                                item.ItemName = roomES.RoomExtraServiceDescription;
                                item.ItemDescription = roomES.RoomExtraServiceDescription;
                                DateTime dateTemp = roomES.CreatedDate ?? default(DateTime);
                                item.ItemDate = dateTemp.AddHours(currentHotel.TimeZoneOffset / 60);
                                item.ItemQuantity = roomES.Quantity;
                                item.ItemPrice = roomES.Amount;
                                item.ItemTotal = roomES.Amount * roomES.Quantity;
                                item.ItemType = roomES.RoomExtraServiceName;
                                context.ReportItems.InsertOnSubmit(item);
                            }
                        }
                    }
                }

                if (!currentReservation.Foc)
                {
                    if (currentReservation.DiscountFlat > 0 || currentReservation.DiscountPercentage > 0)
                    {
                        ReservationRooms reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
                        if (reservationRooms.DiscountFlat > 0)
                        {
                            ReportItems item = new ReportItems();
                            item.ReservationRoomId = model.reservationRoomId;
                            item.ItemName = model.languageKeys["DISCOUNT_MONEY_OFF"].ToString();
                            item.ItemDescription = model.languageKeys["DISCOUNT_MONEY_OFF"].ToString();
                            //DateTime dateTemp = payment.CreatedDate ?? default(DateTime);
                            item.ItemDate = null;
                            item.ItemQuantity = 1;
                            item.ItemPrice = reservationRooms.DiscountFlat;
                            item.ItemTotal = -(decimal?)item.ItemQuantity * item.ItemPrice;
                            item.ItemType = "DISCOUNT";
                            context.ReportItems.InsertOnSubmit(item);
                        }
                        if (reservationRooms.DiscountPercentage > 0)
                        {
                            ReportItems item = new ReportItems();
                            item.ReservationRoomId = model.reservationRoomId;
                            item.ItemName = model.languageKeys["DISCOUNT_PERCENT_OFF"].ToString() + " (" + model.DiscountPercentage.ToString() + "%)"; ;
                            item.ItemDescription = model.languageKeys["DISCOUNT_PERCENT_OFF"].ToString() + " (" + model.DiscountPercentage.ToString() + "%)";
                            item.ItemDate = null;
                            item.ItemQuantity = 1;
                            item.ItemPrice = planListDateRange.discountPercentageAmount;
                            item.ItemTotal = -(decimal?)item.ItemQuantity * item.ItemPrice;
                            item.ItemType = "DISCOUNT";
                            context.ReportItems.InsertOnSubmit(item);
                        }
                    }
                }
                else
                {
                    ReportItems item = new ReportItems();
                    item.ReservationRoomId = model.reservationRoomId;
                    item.ItemName = model.languageKeys["FREE"].ToString();
                    item.ItemDescription = model.languageKeys["FREE"].ToString();
                    item.ItemDate = null;
                    item.ItemQuantity = null;
                    item.ItemPrice = 0;
                    item.ItemTotal = planListDateRange.focAmount;
                    item.ItemType = "DISCOUNT";
                    context.ReportItems.InsertOnSubmit(item);
                }

                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CalculateRoomPrice")]
        public async Task<IHttpActionResult> CalculateRoomPrice(CalculateRoomPrice model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            return Ok(await RoomPriceUtilities.CalculateRoomPrice(model));
        }

        private struct rType
        {
            public int[] AvailableRooms
            {
                get; set;
            }

            public int HotelId
            {
                get; set;
            }

            public int RoomTypeId
            {
                get; set;
            }

            public string RoomTypeName
            {
                get; set;
            }

            public string RoomTypeCode
            {
                get; set;
            }

            public int RoomCount
            {
                get; set;
            }
        };

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("FutureInventory")]
        public async Task<IHttpActionResult> GetFutureInventory(DateTime from, DateTime to)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            from = from.AddMinutes(-currentHotel.TimeZoneOffset);
            to = to.AddMinutes(-currentHotel.TimeZoneOffset);
          
            var RoomAvailabilityMatrix = Utilities.GetRoomAvailabilityMatrix(from, to);
            to = to.AddDays(1);
            var daysBetween = (to - from).Days;

            var roomTypes = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.IsHidden == false && rt.IsDeleted == false).Select(rt => new rType { HotelId = (int)rt.HotelId, RoomTypeId = rt.RoomTypeId, RoomTypeName = rt.RoomTypeName, RoomTypeCode = rt.RoomTypeCode, RoomCount = rt.RoomsList.Count() }).ToArray();

            var currentDate = from;
            var i = 0;
            for (var idx = 0; idx < roomTypes.Count(); idx++)
            {
                roomTypes[idx].AvailableRooms = new int[daysBetween];
            }

            while (currentDate < to)
            {
                foreach (var rt in roomTypes)
                {
                    IEnumerable<DataRow> AvailableRoomsRow =
                    from order in RoomAvailabilityMatrix.AsEnumerable()
                    where order.Field<int>("RoomTypeId") == rt.RoomTypeId
                        && order.Field<DateTime>("Dates") >= currentDate 
                        && order.Field<DateTime>("Dates") < currentDate.AddDays(1)
                    select order;

                    var CanBeSold = (int)AvailableRoomsRow.FirstOrDefault()["CanBeSold"];

                    rt.AvailableRooms[i] = CanBeSold;
                }
                currentDate = currentDate.AddDays(1);
                i++;
            }
            return Ok(roomTypes );
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("TotalPaymentByDay")]
        public async Task<IHttpActionResult> GetTotalPaymentByDay(DateTime from)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            DateTime to = from.AddDays(1);
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();

            /*
            var tmpTotalPayment = context.Payments.Where(p => p.HotelId == user.HotelId && p.CreatedDate >= from && p.CreatedDate <= to && p.PaymentTypeName != "DELETED")
                .Join(context.Payments.Where(rp => rp.HotelId == user.HotelId && rp.RefPaymentId > 0), t => t.RefPaymentId, p => p.PaymentId, (t, p) => new { ldelpay = t, lpay = p })
                .SelectMany(ldp => ldp.ldelpay.PaymentDescription.DefaultIfEmpty(), (x, y) => new {x=x, y }  )
                .Where(m=>m.x.ldelpay.RefPaymentId==null)
                .Sum(am =>am.x.lpay.Amount);*/

            var tmpTotalPayment = context.Payments.Where(pay => pay.HotelId == user.HotelId && pay.CreatedDate >= from && pay.CreatedDate < to).Sum(apay => apay.Amount);

            var retval = new
            {
                Date = from,
                TotalPayment = tmpTotalPayment
            };
            return Ok(retval);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RevenueRoomCheckout")]
        public async Task<IHttpActionResult> GetRevenueRoomCheckout(DateTime from)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();

            var firstDayOfMonth = new DateTime(from.Year, from.Month, 1).Date;
            var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1).Date;
            List<RevenueMonthChart> listRevenueMonth = new List<RevenueMonthChart>();
            DateTime _date = firstDayOfMonth;
            while (DateTime.Compare(_date, lastDayOfMonth) <= 0)
            {
                var item = new RevenueMonthChart();
                item.Date = _date.Date;
                item.Day = _date.Day;
                item.Amount = 0;
                listRevenueMonth.Add(item);
                _date = _date.AddDays(1);
            }

            firstDayOfMonth = firstDayOfMonth.AddMinutes(-currentHotel.TimeZoneOffset);
            DateTime to = lastDayOfMonth.AddDays(1);

            var tmpRevenue = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.DepartureDate >= firstDayOfMonth && rr.DepartureDate < to && rr.BookingStatus == "CHECKOUT")
                .Join(context.Payments, p => p.ReservationRoomId, c => c.ReservationRoomId, (p, c) => new { Date = p.DepartureDate.Value.AddMinutes(currentHotel.TimeZoneOffset).Date, Amount = c.Amount }).ToList()
                .Select(o => new
                {
                    Date = o.Date,
                    Amount = o.Amount
                }).ToList().GroupBy(g => g.Date).Select(s => new
                {
                    Date = s.Key,
                    Amount = s.Sum(p => p.Amount)
                }

                );

            foreach (var item in tmpRevenue)
            {
                foreach (RevenueMonthChart obj in listRevenueMonth)
                {
                    if (obj.Date == item.Date)
                    {
                        obj.Amount = (float)item.Amount;
                        break;
                    }
                }
            }

            var retval = new
            {
                listRevenueMonth = listRevenueMonth
            };

            return Ok(retval);
        }

        public class RevenueMonthChart
        {
            public DateTime Date { get; set; }
            public int Day { get; set; }
            public float Amount { get; set; }
        }

        public class ReservationCompany
        {
            public Company Company { get; set; }
            public int RRID { get; set; }
        }

        public class ReservationSource
        {
            public Source Source { get; set; }
            public int RRID { get; set; }
        }

        public class ReservationMarket
        {
            public Market Market { get; set; }
            public int RRID { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewCompanyToReservation")]
        public IHttpActionResult AddNewCompanyToReservation(ReservationCompany model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            model.Company.IsAvailable = true;
            model.Company.CreatedDate = DateTime.UtcNow;
            model.Company.CreatedUserId = user.UserId;
            model.Company.HotelId = user.HotelId;
            model.Company.SourceId = model.Company.SourceId == 0 ? null : model.Company.SourceId;
            context.Company.InsertOnSubmit(model.Company);

            var oldReservation =
                context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.RRID)
                    .FirstOrDefault();
            if (oldReservation != null)
            {
                var reservation = oldReservation.Reservations;
                if (reservation != null)
                {
                    reservation.Company = model.Company;
                }
                
            }
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Company);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewSourceToReservation")]
        public async Task<IHttpActionResult> AddNewSourceToReservation(ReservationSource model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            model.Source.IsAvailable = true;
            model.Source.CreatedDate = DateTime.UtcNow;
            model.Source.CreatedUserId = user.UserId;
            model.Source.HotelId = user.HotelId;

            context.Source.InsertOnSubmit(model.Source);
            //context.SubmitChanges();
            //Elastic.IndexLastAudit(context);

            var oldReservation =
                context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.RRID)
                    .FirstOrDefault();
            if (oldReservation != null)
            {
                var reservation = oldReservation.Reservations;
                if (reservation != null)
                {
                    reservation.Source = model.Source;
                }
                
            }
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Source);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewMarketToReservation")]
        public async Task<IHttpActionResult> AddNewMarketToReservation(ReservationMarket model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            model.Market.IsAvailable = true;
            model.Market.CreatedDate = DateTime.UtcNow;
            model.Market.CreatedUserId = user.UserId;
            model.Market.HotelId = user.HotelId;

            context.Market.InsertOnSubmit(model.Market);
            //context.SubmitChanges();
            //Elastic.IndexLastAudit(context);

            var oldReservation =
                context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.RRID)
                    .FirstOrDefault();
            if (oldReservation != null)
            {
                var reservation = oldReservation.Reservations;
                reservation.Market = model.Market;
               
            }
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Market);
           
        }

        public class BusinessModel
        {
            public int RRID { get; set; }
            public Company Company { get; set; }
            public Source Source { get; set; }
            public Market Market { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveBusiness")]
        public async Task<IHttpActionResult> SaveBusiness(BusinessModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            var oldRR =
                context.ReservationRooms.FirstOrDefault(
                    rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.RRID);
            if (oldRR != null && oldRR.Reservations != null)
            {
                oldRR.Reservations.MarketId = model.Market?.MarketId ?? null;
                oldRR.Reservations.SourceId = model.Source?.SourceId ?? null;
                oldRR.Reservations.CompanyId = model.Company?.CompanyId ?? null;

                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        #region Quick CheckOut

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetQuickCheckOut")]
        public async Task<IHttpActionResult> getQuickCheckOut(int reservationRoomId)
        {
            var startTime = DateTime.Now;
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var allUsers = UserUtitily.getHotelUsers(context, currentClientUser.HotelId);
            var allUsersDic = allUsers.ToDictionary(p => p.Id, p => p);
            var memcache = new Common.MemoryCacher();
            var quickCheckOut = memcache.GetValue("QUICKCHECKOUT" + reservationRoomId);
            if (quickCheckOut != null)
            {
                Type t = quickCheckOut.GetType();
                PropertyInfo r = t.GetProperty("RoomPrice");
                PropertyInfo rr = t.GetProperty("Reservation");
                PropertyInfo apc = t.GetProperty("applyPastCheckOut");
                PropertyInfo es = t.GetProperty("ListExtraService");
                PropertyInfo fi = t.GetProperty("FormInvoice");
                PropertyInfo ipc = t.GetProperty("IsPreCheckOut");
                var IsPreCheckOut = ipc.GetValue(quickCheckOut, null);
                var Reservation = rr.GetValue(quickCheckOut, null);
                var FormInvoice = fi.GetValue(quickCheckOut, null);
                var ExtraService = es.GetValue(quickCheckOut, null);

                var RoomPrice = (CalculateRoomPrice) r.GetValue(quickCheckOut, null);
                var applyPastCheckOut = (bool)apc.GetValue(quickCheckOut, null);



                if (!applyPastCheckOut)
                {
                    RoomPrice.departureDate = DateTime.UtcNow;
                }

                var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(RoomPrice);

                
                var cache = new
                {
                    CalculateRoomPrice = planListDateRange,
                    ListExtraService = ExtraService,
                    FormInvoice = FormInvoice,
                    Reservation = Reservation,
                    IsPreCheckOut = IsPreCheckOut,
                    RoomPrice = RoomPrice,
                    applyPastCheckOut = applyPastCheckOut
                };
                //check pre checkout 
                return Ok(cache);
            }
            else {
                //Extra service
                var cacheExtraService = memcache.GetValue("EXTRASERVICES_" + currentClientUser.HotelId);
                object ExtraService;
                if (cacheExtraService != null)
                {
                    ExtraService = cacheExtraService;
                }
                else {
                    var es = context.ExtraServiceTypes.Where(r => r.HotelId == currentClientUser.HotelId);
                    var escats = context.ExtraServiceCategories.Where(r => r.HotelId == currentClientUser.HotelId && !r.IsHidden);
                    var esitems = context.ExtraServiceItems.Where(r => r.HotelId == currentClientUser.HotelId && r.IsHidden == false && escats.Contains(r.ExtraServiceCategories));
                    ExtraService = new
                    {
                        ExtraServiceTypes = es,
                        ExtraServiceCategories = escats,
                        ExtraServiceItems = esitems
                    };
                    memcache.AddByHotelId(currentClientUser.HotelId, "EXTRASERVICES_" + currentClientUser.HotelId, ExtraService, DateTimeOffset.UtcNow.AddHours(1));
                }
                //Form Invoice
                var hotelFormRoomInvoice = context.HotelForm.Where(hf => hf.HotelId == currentClientUser.HotelId && hf.FormType == "RoomInvoice").FirstOrDefault();

                //Reservation
                var currentHotel = context.Hotels.Where(h => h.HotelId == currentClientUser.HotelId).FirstOrDefault();
                var reservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId == reservationRoomId)
                    .Select(r => new
                    {
                        room = r,
                        customer = r.Travellers,
                        reservationNumber = r.Reservations.ReservationNumber,
                        reservation = r.Reservations
                    }
                    ).FirstOrDefault();

                var applyPastCheckOut = false;
                var pastCheckOutReasonTemp = "";

                var pastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == currentClientUser.HotelId && pt.ReservationRoomId == reservationRoomId).FirstOrDefault();
                if (pastCheckOut != null)
                {
                    applyPastCheckOut = true;
                    pastCheckOutReasonTemp = pastCheckOut.PastCheckOutReason;
                }

                var pastCheckOutReason = pastCheckOutReasonTemp;
                if (reservation.customer.CountryId == null)
                {
                    var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                    reservation.customer.CountryId = country.CountryId;
                }
                var roomInfo = new Rooms();
                if (reservation.room.RoomId != null)
                {
                    roomInfo = context.Rooms.Where(rm => rm.HotelId == currentClientUser.HotelId && rm.RoomId == reservation.room.RoomId).FirstOrDefault();
                }
                var roomTypeInfo = context.RoomTypes.Where(rt => rt.HotelId == currentClientUser.HotelId && rt.RoomTypeId == reservation.room.RoomTypeId).FirstOrDefault();
                var planInfo = new RoomPrices();
                if (reservation.room.RoomPriceId != null)
                {
                    planInfo = context.RoomPrices.Where(rp => rp.HotelId == currentClientUser.HotelId && rp.RoomPriceId == reservation.room.RoomPriceId).FirstOrDefault();
                }
                var roomExtraServices = context.RoomExtraServices.Where(i => i.HotelId == currentClientUser.HotelId && i.ReservationRoomId == reservationRoomId).ToList();
                var roomExtraServiceInfo = new List<RoomExtraServiceCreatedUserInfo>();
                foreach (var roomES in roomExtraServices)
                {
                    RoomExtraServiceCreatedUserInfo infoTemp = new RoomExtraServiceCreatedUserInfo();
                    infoTemp.RoomExtraServiceId = roomES.RoomExtraServiceId;
                    infoTemp.UserName = allUsersDic[roomES.CreatedUserId].UserName;
                    if (roomES.IsDeleted)
                    {
                        infoTemp.UserNameDeleted = allUsersDic[roomES.DeletedBy].UserName;
                    }
                    roomExtraServiceInfo.Add(infoTemp);
                }
                var roomExtraServiceItems = context.RoomExtraServiceItems.Where(resi => resi.HotelId == currentClientUser.HotelId && resi.ReservationRoomId == reservationRoomId).ToList();
                var roomExtraServiceItemInfo = new List<RoomExtraServiceItemCreatedUserInfo>();
                foreach (var roomESI in roomExtraServiceItems)
                {
                    if (roomESI.IsDeleted)
                    {
                        RoomExtraServiceItemCreatedUserInfo infoTemp = new RoomExtraServiceItemCreatedUserInfo();
                        infoTemp.RoomExtraServiceItemId = roomESI.RoomExtraServiceItemId;
                        infoTemp.UserName = allUsersDic[roomESI.DeletedBy].UserName;
                        roomExtraServiceItemInfo.Add(infoTemp);
                    }
                }
                var extraServices = context.ExtraServiceTypes.Where(r => r.HotelId == currentClientUser.HotelId).ToList();
                var esCat = context.ExtraServiceCategories.Where(c => c.HotelId == currentClientUser.HotelId && !c.IsHidden).ToList();
                var extraServiceItems = context.ExtraServiceItems.Where(r => r.HotelId == currentClientUser.HotelId && !r.IsHidden && esCat.Contains(r.ExtraServiceCategories)).ToList();
                var payments = context.Payments.Where(p => p.HotelId == currentClientUser.HotelId && p.ReservationRoomId == reservationRoomId).ToList();
                var paymentInfo = new List<PaymentInfo>();
                foreach (var payment in payments)
                {
                    PaymentInfo infoTemp = new PaymentInfo();
                    infoTemp.PaymentId = payment.PaymentId;
                    infoTemp.UserName = allUsersDic[payment.CreatedUserId].UserName;
                    paymentInfo.Add(infoTemp);
                }
                var currencies = context.Money.Where(mon => mon.HotelId == currentClientUser.HotelId).ToList();
                var currenciesDict = context.Currencies.ToDictionary(c => c.CurrencyId, c => c);
                var currenciesISO = new List<Currencies>();
                foreach (var currency in currencies)
                {
                    var iso = currenciesDict[(int)currency.CurrencyId];
                    if (iso != null)
                    {
                        currenciesISO.Add(iso);
                    }
                }
                var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
                var paymentMethods = context.PaymentMethods.Where(pay => pay.PaymentMethodId == pay.PaymentMethodId).ToList();
                var sharer = context.ReservationTravellers.Where(rt => rt.ReservationRoomId == reservation.room.ReservationRoomId).ToList();
                var sharerDict = sharer.ToDictionary(s => s.TravellerId, s => s);
                var sharerRDict = sharer.ToDictionary(s => s.ReservationTravellerId, s => s);
                var allCustomers = context.Travellers.Where(t => sharerDict.Keys.Contains(t.TravellerId)).ToDictionary(t => t.TravellerId, t => t);
                var allResTraEI = context.ReservationTravellerExtraInformation.Where(rtei => rtei.HotelId == currentClientUser.HotelId && sharerRDict.Keys.Contains((int)rtei.ReservationTravellerId)).ToDictionary(rtei => rtei.ReservationTravellerId, rtei => rtei);
                List<SharerViewModel> sharerList = new List<SharerViewModel>();
                foreach (var sha in sharer)
                {
                    SharerViewModel temp = new SharerViewModel();
                    temp.customer = allCustomers[(int)sha.TravellerId]; //context.Travellers.Where(s => s.HotelId == currentClientUser.HotelId && s.TravellerId == sha.TravellerId).FirstOrDefault();
                    if (temp.customer.CountryId == null)
                    {
                        var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                        temp.customer.CountryId = country.CountryId;
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                    }
                    temp.reservationRoomId = reservationRoomId;

                    ReservationTravellerExtraInformation travellerExtra = allResTraEI[sha.ReservationTravellerId];
                    if (travellerExtra == null)
                    {
                        travellerExtra = new ReservationTravellerExtraInformation();
                        travellerExtra.HotelId = currentClientUser.HotelId;
                        travellerExtra.ReservationTravellerId = sha.ReservationTravellerId;
                        travellerExtra.IsChild = false;
                        context.ReservationTravellerExtraInformation.InsertOnSubmit(travellerExtra);
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                    }
                    temp.travellerExtraInfo = travellerExtra;
                    sharerList.Add(temp);
                }
                List<Countries> countries = context.Countries.Where(c => c.CountryId == c.CountryId).ToList();
                List<RoomRemarks> roomRemarks = context.RoomRemarks.Where(rrm => rrm.HotelId == currentClientUser.HotelId && rrm.ReservationRoomId == reservationRoomId).ToList();
                List<RoomBreakfast> roomBreakfast = context.RoomBreakfast.Where(rb => rb.HotelId == currentClientUser.HotelId && rb.ReservationRoomId == reservationRoomId).ToList();

                var market = context.Market.FirstOrDefault(mar => mar.HotelId == currentClientUser.HotelId && mar.MarketId == reservation.reservation.MarketId);
                var source =
                    context.Source.FirstOrDefault(
                        mar => mar.HotelId == currentClientUser.HotelId && mar.SourceId == reservation.reservation.SourceId);
                var company =
                    context.Company.FirstOrDefault(
                        mar => mar.HotelId == currentClientUser.HotelId && mar.CompanyId == reservation.reservation.CompanyId);
                var Reservation = new 
                {
                    applyPastCheckOut = applyPastCheckOut,
                    pastCheckOutReason = pastCheckOutReason,
                    room = reservation.room,
                    reservationNumber = reservation.reservationNumber,
                    planInfo = planInfo,
                    roomInfo = roomInfo,
                    roomTypeInfo = roomTypeInfo,
                    customer = reservation.customer,
                    sharerList = sharerList,
                    roomExtraServices = roomExtraServices,
                    roomExtraServiceInfo = roomExtraServiceInfo,
                    roomExtraServiceItems = roomExtraServiceItems,
                    roomExtraServiceItemInfo = roomExtraServiceItemInfo,
                    extraServices = extraServices,
                    extraServiceItems = extraServiceItems,
                    Payments = payments,
                    PaymentInfo = paymentInfo,
                    currencies = currencies,
                    currenciesISO = currenciesISO,
                    defaultCurrency = new
                    {
                        MoneyId = defaultCurrency.MoneyId,
                        MoneyName = defaultCurrency.MoneyName
                    },
                    paymentMethods = paymentMethods,
                    countries = countries,
                    roomRemarks = roomRemarks,
                    roomBreakfast = roomBreakfast,
                    company = company,
                    source = source,
                    market = market
                };

                //CalculateRoomPrice
                CalculateRoomPrice RoomPrice = new CalculateRoomPrice()
                {
                    roomId = Reservation.room.RoomId.Value,
                    arrivalDate = Reservation.room.ArrivalDate.Value,
                    departureDate = DateTime.UtcNow,
                    adults = Reservation.room.Adults,
                    children = Reservation.room.Child,
                    RoomPriceId = Reservation.room.RoomPriceId,
                    FOC = Reservation.room.Foc,
                    DiscountPercentage = (float)Reservation.room.DiscountPercentage,
                    DiscountFlat = Reservation.room.DiscountFlat,
                    Price = Reservation.room.Price,
                    reservationRoomId = Reservation.room.ReservationRoomId,
                    roomTypeId = (int)Reservation.room.RoomTypeId
                };
                if (applyPastCheckOut)
                {
                    RoomPrice.departureDate = reservation.room.DepartureDate.Value;
                }

                var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(RoomPrice);
                //check pre checkout 
                bool IsPreCheckOut = false;
                var ChangeReservationStatus = context.ChangeReservationStatus.Where(m => m.ReservationRoomId == reservationRoomId && m.ActionCode == "PRE_CHECKOUT").ToList();

                if (ChangeReservationStatus.Count() > 0)
                {
                    IsPreCheckOut = true;
                }
                //cache
                var cache = new
                {
                    CalculateRoomPrice = planListDateRange,
                    ListExtraService = ExtraService,
                    FormInvoice = hotelFormRoomInvoice,
                    Reservation = Reservation,
                    IsPreCheckOut = IsPreCheckOut,
                    RoomPrice = RoomPrice,
                    applyPastCheckOut = applyPastCheckOut                    
                };
                
                memcache.AddByHotelId(currentClientUser.HotelId, "QUICKCHECKOUT" + reservationRoomId, cache, DateTimeOffset.UtcNow.AddHours(1));
                return Ok(cache);
            }
            
            
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessQuickCheckOut")]
        public async Task<IHttpActionResult> processQuickCheckOut(QuickCheckOut Model)
        {
            if (Model.RoomData != null && Model.RoomData.room != null)
            {
                if (Utilities.CheckRoomIsCheckout(Model.RoomData.room.ReservationRoomId) == true)
                {
                    return BadRequest("CAN_NOT_PROCESS_BECAUSE_ROOM_WAS_CHEKCOUT");
                }
            }


            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == currentClientUser.HotelId).FirstOrDefault();
            var data = Model.RoomData;
            if (data.room != null && data.room.ReservationRoomId != 0)
            {
                if (data.room.ArrivalDate != null && data.room.DepartureDate != null && data.room.ArrivalDate < data.room.DepartureDate)
                {
                    if (data.room.RoomId > 0)
                    {
                        //var conflictReservation = currentHotel.ReservationRoomsList.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId != data.room.ReservationRoomId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (data.room.BookingStatus == "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && DateTime.UtcNow <= r.DepartureDate)) || (data.room.BookingStatus != "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate)))).FirstOrDefault();
                        var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == currentClientUser.HotelId && r.ReservationRoomId != data.room.ReservationRoomId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (data.room.BookingStatus == "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && DateTime.UtcNow <= r.DepartureDate)) || (data.room.BookingStatus != "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate)))).FirstOrDefault();
                        if (conflictReservation != null)
                        {
                            ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                            return Content(HttpStatusCode.BadRequest, conflictReservation);
                        }
                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            // Check conflict voi Room Repair trong truong hop Room Move
                            var arrivalDateTemp = data.room.ArrivalDate;
                            var roomMoveMostRecently = currentHotel.ReservationRoomsList.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault().RoomMoveList;
                            if (roomMoveMostRecently != null && roomMoveMostRecently.Count > 0)
                            {
                                arrivalDateTemp = roomMoveMostRecently.Max(rm => rm.MoveDate);
                            }
                            var conflictRoomRepair = currentHotel.RoomRepairList.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && arrivalDateTemp <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                return BadRequest("CAN_NOT_CHECK_OUT_REPAIRING_ROOM");
                            }
                        }
                    }

                    #region Check Out
                    var RRTemp = new ReservationRooms();
                    //ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId && rr.HotelId == currentClientUser.HotelId).FirstOrDefault();
                    var oldRR = currentHotel.ReservationRoomsList.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                    if (oldRR != null)
                    {
                        var arrivalDate = oldRR.ArrivalDate;
                        var departureDate = oldRR.DepartureDate;
                        var roomTypeId = oldRR.RoomTypeId;
                        RRTemp.ArrivalDate = arrivalDate;
                        RRTemp.DepartureDate = departureDate;
                        RRTemp.RoomTypeId = roomTypeId;

                        // CHECKOUT VERIFY PROCESS
                        var model = new CalculateRoomPrice();
                        model.roomId = data.room.RoomId ?? 0;
                        model.reservationRoomId = data.room.ReservationRoomId;
                        model.adults = data.room.Adults;
                        model.children = data.room.Child;
                        model.RoomPriceId = data.room.RoomPriceId;
                        model.FOC = data.room.Foc;
                        model.DiscountFlat = data.room.DiscountFlat;
                        model.DiscountPercentage = (float)data.room.DiscountPercentage;
                        model.languageKeys = data.languageKeys;
                        model.Price = data.room.Price;
                        model.roomTypeId = (int)oldRR.RoomTypeId;
                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            //var oldPastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == currentClientUser.HotelId && pt.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                            var oldPastCheckOut = oldRR.PastCheckOutList.FirstOrDefault();
                            if (oldPastCheckOut != null)
                            {
                                if (data.room.DepartureDate >= DateTime.UtcNow)
                                {
                                    return BadRequest("INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT");
                                }
                                else
                                {
                                    model.departureDate = data.room.DepartureDate ?? default(DateTime);
                                }
                            }
                            else
                            {
                                model.departureDate = DateTime.UtcNow;
                            }
                            model.arrivalDate = data.room.ArrivalDate ?? default(DateTime);
                        }

                        #region Payment

                        if (Model.Payments != null && oldRR.BookingStatus != "CHECKOUT" )
                        {
                            var payment = Model.Payments.payment;
                            payment.HotelId = currentClientUser.HotelId;
                            payment.CreatedDate = DateTime.UtcNow;
                            payment.CreatedUserId = currentClientUser.UserId;
                            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
                            {
                                payment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(currentClientUser.HotelId, payment.PaymentTypeName);
                                Notification.processNotificationAddNewPayment(Model.Payments,currentClientUser);                           
                                context.Payments.InsertOnSubmit(payment);
                            }
                            context.SubmitChanges();
                            //Common.Elastic.IndexLastAudit(context);
                        }

                        #endregion Payment



                        // CHECKOUT LEGAL
                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(model);
                            var roomExtraServices = context.RoomExtraServices.Where(rex => rex.HotelId == currentClientUser.HotelId && rex.ReservationRoomId == data.room.ReservationRoomId && !rex.IsDeleted).ToList();
                            //var payments = context.Payments.Where(p => p.HotelId == currentClientUser.HotelId && p.ReservationRoomId == data.room.ReservationRoomId).ToList();
                            var payments = oldRR.PaymentsList;
                            var totalPayment = payments.Sum(p => p.Amount);
                            var totalRoomPrice = planListDateRange.totalPrice + roomExtraServices.Sum(rex => rex.Amount*rex.Quantity);
                            int currentMinorUnit = Convert.ToInt16(currentHotel.MoneyList.Where(mon => mon.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault().Currencies.MinorUnit.ToString());
                            var roundMoney = Math.Round(totalRoomPrice.Value - totalPayment.Value, currentMinorUnit);
                            if (roundMoney == 0)
                            {
                                oldRR.DepartureDate = model.departureDate;
                                //var changeReservationStatus = context.ChangeReservationStatus.Where(change => change.HotelId == currentClientUser.HotelId && change.ReservationRoomId == data.room.ReservationRoomId && change.ActionCode == "PRE_CHECKOUT").FirstOrDefault();
                                var changeReservationStatus = oldRR.ChangeReservationStatusList.Where(change => change.ActionCode == "PRE_CHECKOUT").FirstOrDefault();
                                if (changeReservationStatus != null)
                                {
                                    oldRR.CheckOutDate = changeReservationStatus.ActionPoint;
                                }
                                else
                                {
                                    oldRR.CheckOutDate = DateTime.UtcNow;
                                }
                                oldRR.CheckOutUserId = currentClientUser.UserId;

                                //Rooms room = context.Rooms.Where(r => r.HotelId == currentClientUser.HotelId && r.RoomId == oldRR.RoomId).FirstOrDefault();
                                var room = oldRR.Rooms;
                                room.HouseStatus = "DIRTY";

                                // CREATE ROOM INVOICE PROCESS
                                await CreateRoomInvoice(model);
                                oldRR.BookingStatus = "CHECKOUT";

                                context.SubmitChanges();

                                var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                                ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, currentClientUser, context);
                                ReservationUtility.RebuildRoomCharges(dateRange, oldRR, currentClientUser, context);

                                //Notification.sendNotificationToDevice(currentClientUser.UserName.ToLower(), currentClientUser.FullName + " Checkout " + room.RoomName + " ", currentClientUser.HotelId, "NOTIFICATION_CHECKOUT");
                                Notification.processNotificationCheckout(currentClientUser, room.RoomName);
                                

                                // Consider only if hotel is using module "Channel Mananger"
                                // Room Available
                                if (RRTemp != null)
                                {
                                    // Update matrix for original period 
                                    ReservationUtility.RebuildAvailableRoom(RRTemp, currentClientUser, context);
                                }
                                //ReservationUtility.RebuildAvailableRoom(oldRR, currentClientUser, context);

                                //Send sms to guest
                                SMSMobifone.sendSMSNotificationCheckOut(oldRR);
                            }
                            else
                            {
                                // Reset Cache if have payment but not balance
                                Common.Elastic.IndexLastAudit(context);
                                return BadRequest("CHECKOUT_IS_NOT_VALID");
                            }

                           
                        }
                        Common.Elastic.IndexLastAudit(context);
                        return Ok(data.room.ReservationRoomId);
                    }
                    else return BadRequest("RESERVATION_DOES_NOT_EXIST");

                    #endregion Check Out
                }
                else
                    return BadRequest("PLEASE_SELECT_ARRIVAL/DEPARTURE_DATE");
            }
            //Elastic.IndexLastAudit(context);
            return Ok();
        }


        public class QuickCheckOut
        {
            public PaymentModel Payments { get; set; }
            public SaveRoomData RoomData { get; set; }
        }

        #endregion Quick CheckOut
        #region ReservationRoom
        [HttpGet]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ReservationRoom")]
        public async Task<IHttpActionResult> ReservationRoom(DateTime date, int? reservationRoomId)
        {
            var startTime = DateTime.Now;
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            object reservationInfo = null;
            PlanListDateRange CalculateRoomPrice = null;
            CalculateRoomPrice RoomPrice = null;
            if (reservationRoomId != null)
            {
                var RoomReservationCache = memCache.GetValue("ROOMRESERVATION_" + reservationRoomId.Value);
                if (RoomReservationCache != null)
                {
                    #region CalculateRoomPrice
                    Type t = RoomReservationCache.GetType();

                    PropertyInfo ri = t.GetProperty("RoomInvoice");
                    PropertyInfo rs = t.GetProperty("RoomStatus");
                    PropertyInfo ac = t.GetProperty("AllCustomer");
                    PropertyInfo _es = t.GetProperty("ExtraService");
                    PropertyInfo r = t.GetProperty("reservationInfo");
                    PropertyInfo rp = t.GetProperty("RoomPrice");
                    //
                    var reservationInfoTmp = r.GetValue(RoomReservationCache, null);
                    var roomInvoice = ri.GetValue(RoomReservationCache, null);
                    var roomStatus = rs.GetValue(RoomReservationCache, null);
                    var allCustomer = ac.GetValue(RoomReservationCache, null);
                    var extraService = _es.GetValue(RoomReservationCache, null);
                    //
                    var Reservation = reservationInfoTmp.ToDictionary();
                    var applyPastCheckOut = (bool)Reservation["applyPastCheckOut"];
                    var reservationTmp = (ReservationRooms)Reservation["room"];
                    var RoomPriceTmp = (CalculateRoomPrice)rp.GetValue(RoomReservationCache, null);
                    PlanListDateRange CalculateRoomPriceTmp =null ;
                    if (RoomPriceTmp != null)
                    {
                        if (applyPastCheckOut)
                        {
                            RoomPriceTmp.departureDate = reservationTmp.DepartureDate.Value;
                        }
                        if (reservationTmp.BookingStatus == "BOOKED" || reservationTmp.BookingStatus == "NOSHOW")
                        {
                            RoomPriceTmp.departureDate = reservationTmp.DepartureDate.Value;
                        }
                        CalculateRoomPriceTmp = await RoomPriceUtilities.CalculateRoomPrice(RoomPriceTmp);
                    }
                    
                    return Ok(new
                    {
                        RoomInvoice= roomInvoice,
                        RoomStatus = roomStatus,
                        AllCustomer = allCustomer,
                        ExtraService= extraService,
                        reservationInfo= reservationInfoTmp,
                        CalculateRoomPrice= CalculateRoomPriceTmp,
                        RoomPrice= RoomPriceTmp
                    });
                    
                    #endregion
                }
            }
            #region Room Status
            var currentTime = DateTime.Now;
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            date = date.AddMinutes(-currentHotel.TimeZoneOffset);
            //DataTable AvailableRooms = new DataTable();
            //AvailableRooms = Utilities.GetAvailableRooms(date, date);
            //var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false && room.RoomTypes.IsHidden == false).
            var roomList = currentHotel.RoomsList.Where(room => room.IsHidden == false && room.RoomTypes.IsHidden == false).
                Select(rm => new
                {
                    Room = rm,
                    RoomType = rm.RoomTypes,
                    RoomRepairList = rm.RoomRepairList.Where(rpl => rpl.IsDeleted == false).ToList()
                }).ToList();
            //var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId != null && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
            var bookingList = currentHotel.ReservationRoomsList.Where(r => r.RoomId != null && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new
                    {
                        r.BookingStatus,
                        r.Adults,
                        r.ArrivalDate,
                        r.Child,
                        r.DepartureDate,
                        r.Reservations,
                        Travellers = new
                        {
                            r.Travellers.Fullname,
                            r.Travellers.TravellerId
                        },
                        r.RoomId,
                        r.ReservationRoomId,
                        r.TravellersList,
                        r.Foc,
                        r.DiscountPercentage,
                        r.DiscountFlat,
                        r.RoomPriceId,
                    }).ToList();
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId &&
                ((rr.ArrivalDate <= date.AddDays(1) && rr.DepartureDate >= date) ||
                (rr.ArrivalDate <= date && rr.BookingStatus == "CHECKIN")))
                .Select(rr => new
                {
                    rr.BookingStatus,
                    rr.Adults,
                    rr.ArrivalDate,
                    rr.Child,
                    rr.DepartureDate,
                    rr.Reservations,
                    rr.TravellerId,
                    Travellers = new
                    {
                        rr.Travellers.Fullname,
                        rr.Travellers.TravellerId,
                        rr.Travellers.Countries.CountryName,
                        rr.Travellers.Countries.CountryCode
                    },
                    rr.RoomId,
                    rr.ReservationRoomId,
                    rr.TravellersList,
                    rr.Foc,
                    rr.DiscountPercentage,
                    rr.DiscountFlat,
                    rr.RoomPriceId,
                    rr.Price,
                    rr.Note,
                    rr.Reservations.Company,
                    rr.Reservations.Source,
                    rr.Reservations.Market,
            }).ToList();
            List<int> rrIdList = new List<int>();

            foreach (var rr in reservationRooms)
            {
                rrIdList.Add(rr.ReservationRoomId);
            }
            //var allResExtra = context.ReservationTravellerExtraInformation.Where(etxi => etxi.HotelId == user.HotelId).Select(
            //    etxi => new { etxi.IsChild, etxi.ReservationTravellers.TravellerId, etxi.ReservationTravellers.ReservationRoomId }
            //    ).ToList();
            var allResExtra = currentHotel.ReservationTravellerExtraInformationList.Where(etxi => etxi.HotelId == user.HotelId).Select(
                etxi => new { etxi.IsChild, etxi.ReservationTravellers.TravellerId, etxi.ReservationTravellers.ReservationRoomId }
                ).ToList();
            //var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var currencies = currentHotel.MoneyList;
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();

            //group into batch query
            var allRelatedRoomExtraServicesQuery = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRelatedPaymentsQuery = context.Payments.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomMovesQuery = context.RoomMove.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            var allRoomExtraServiceItemsQuery = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));

            var roomTypesQuery = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId && !roomType.IsHidden);
            var planListQuery = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId);
            var statusColorsQuery = context.StatusColors.Where(sc => sc.HotelId == user.HotelId);
            var paymentMethodsQuery = context.PaymentMethods;
            var remarkEventsQuery = context.RemarkEvents;
            var sourceListQuery = context.Source.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var companyListQuery = context.Company.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var marketListQuery = context.Market.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            //
            var travellerQuery = context.Travellers.Where(tvl => tvl.HotelId == user.HotelId);
            var hotelInvoiceQuery = context.HotelForm.Where(hf => hf.HotelId == user.HotelId);
            var esQuery = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId);
            var esCategoryQuery = context.ExtraServiceCategories.Where(r => r.HotelId == user.HotelId && !r.IsHidden);
            var esItemsQuery = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && r.IsHidden == false && esCategoryQuery.Contains(r.ExtraServiceCategories));
            //

            var results2 = context.ExecuteQuery(roomTypesQuery, planListQuery, statusColorsQuery, paymentMethodsQuery,
                                                remarkEventsQuery, sourceListQuery, companyListQuery, marketListQuery,
                                                allRelatedRoomExtraServicesQuery, allRelatedPaymentsQuery, allRoomMovesQuery, allRoomExtraServiceItemsQuery,
                                                travellerQuery, hotelInvoiceQuery, esQuery, esCategoryQuery, esItemsQuery
                                                );

            var roomTypes = results2.GetResult<RoomTypes>().ToList();
            var planList = results2.GetResult<RoomPrices>().ToList();
            var statusColors = results2.GetResult<StatusColors>().ToList();
            var paymentMethods = results2.GetResult<PaymentMethods>().ToList();
            var remarkEvents = results2.GetResult<RemarkEvents>().ToList();
            var sourceList = results2.GetResult<Source>().ToList();
            var companyList = results2.GetResult<Company>().ToList();
            var marketList = results2.GetResult<Market>().ToList();
            var allRoomExtraServiceList = results2.GetResult<RoomExtraServices>().ToList();
            var allRelatedPayments = results2.GetResult<Payments>().ToList();
            var allRoomMoves = results2.GetResult<RoomMove>().ToList();
            var allRoomExtraServiceItemsList = results2.GetResult<RoomExtraServiceItems>().ToList();
            #region All Customer
            List<Travellers> Travellers = results2.GetResult<Travellers>().ToList();
            #endregion
            #region Room Invoice
            var HotelFormTmp = results2.GetResult<HotelForm>().ToList();
            var hotelFormRoomInvoice = HotelFormTmp.Where(hf=>hf.FormType== "RoomInvoice").FirstOrDefault();
            var hotelFormRoomReceipt = HotelFormTmp.Where(hf => hf.FormType == "Receipt").FirstOrDefault();
            //
            var RoomInvoice = new {
                hotelFormRoomInvoice = hotelFormRoomInvoice,
                hotelFormRoomReceipt = hotelFormRoomReceipt
            };
            #endregion
            #region Extra service
            var es = results2.GetResult<ExtraServiceTypes>().ToList();
            var escats= results2.GetResult<ExtraServiceCategories>().ToList();
            var esitems= results2.GetResult<ExtraServiceItems>().ToList();
            var ExtraService = new ExtraServiceList
            {
                ExtraServiceTypes = es,
                ExtraServiceCategories = escats,
                ExtraServiceItems = esitems
            };
            #endregion
            //Data correction methods

            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }
            if (paymentMethods.Count == 0)
            {
                //Auto generate payment methods
                var cash = new PaymentMethods();
                cash.PaymentMethodName = "CASH";
                cash.PaymentMethodDescription = "CASH_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(cash);
                var credit = new PaymentMethods();
                credit.PaymentMethodName = "CREDIT";
                credit.PaymentMethodDescription = "CREDIT_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(credit);
                var banktransfer = new PaymentMethods();
                banktransfer.PaymentMethodName = "BANK_TRANSFER";
                banktransfer.PaymentMethodDescription = "BANK_TRANSFER";
                context.PaymentMethods.InsertOnSubmit(banktransfer);
                var cityledger = new PaymentMethods();
                cityledger.PaymentMethodName = "CITY_LEDGER";
                cityledger.PaymentMethodDescription = "CITY_LEDGER";
                context.PaymentMethods.InsertOnSubmit(cityledger);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            if (remarkEvents.Count == 0)
            {
                RemarkEvents remarkEventCheckIn = new RemarkEvents();
                remarkEventCheckIn.RemarkEventCode = "CHECKIN";
                remarkEventCheckIn.RemarkEventName = "CHECK_IN";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckIn);
                RemarkEvents remarkEventCheckOut = new RemarkEvents();
                remarkEventCheckOut.RemarkEventCode = "CHECKOUT";
                remarkEventCheckOut.RemarkEventName = "CHECK_OUT";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckOut);
                RemarkEvents remarkEventReservation = new RemarkEvents();
                remarkEventReservation.RemarkEventCode = "RESERVATION";
                remarkEventReservation.RemarkEventName = "RESERVATION";
                context.RemarkEvents.InsertOnSubmit(remarkEventReservation);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }

            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }
            var endTime = DateTime.Now;
            var retval = new
            {
                reservationRooms = reservationRooms,
                rooms = roomList,
                BookingList = bookingList,
                roomTypes = roomTypes,
                planList = planList,
                statusColors = statusColors,
                currencies = currencies,
                currenciesISO = currenciesISO,
                allResExtra = allResExtra,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },
                paymentMethods = paymentMethods,
                remarkEvents = remarkEvents,
                sourceList,
                companyList,
                marketList,
                executionTime = (endTime - currentTime).TotalMilliseconds,
                //AvailableRooms = AvailableRooms,
                RelatedPayments = allRelatedPayments,
                RoomMoves = allRoomMoves,
                RoomExtraServicesList = allRoomExtraServiceList,
                RoomExtraServiceItemsList = allRoomExtraServiceItemsList
            };
            #endregion
            #region Reservation
            
            if (reservationRoomId != null)
            {
                List<Staffs> ListUser = context.Staffs.Where(s => s.HotelId == user.HotelId).ToList();
                string hotelOwnerId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().HotelOwnerId;
                var userOwner = context.AspNetUsers.Where(u => u.Id == hotelOwnerId).FirstOrDefault();
                ListUser.Add(
                    new Staffs()
                    {
                        Email = userOwner.Email,
                        UserId = hotelOwnerId
                    });
                var reservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == reservationRoomId)
                    .Select(r => new
                    {
                        room = r,
                        customer = r.Travellers,
                        reservationNumber = r.Reservations.ReservationNumber,
                        reservation = r.Reservations,
                        roomCharges = r.RoomChargesList
                    }).FirstOrDefault();
                var applyPastCheckOut = false;
                var pastCheckOutReasonTemp = "";
                if (reservation.customer.CountryId == null)
                {
                    var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                    reservation.customer.CountryId = country.CountryId;
                    context.SubmitChanges();
                    Common.Elastic.IndexLastAudit(context);
                };
                var roomInfo = new Rooms();
                var planInfo = new RoomPrices();
                //
                var pastCheckOutQuery = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == reservationRoomId);
                var roomInfoQuery = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == reservation.room.RoomId);
                var roomTypeInfoQuery = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.RoomTypeId == reservation.room.RoomTypeId);
                var planInfoQuery = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId && rp.RoomPriceId == reservation.room.RoomPriceId);
                var roomESQuery = context.RoomExtraServices.Where(i => i.HotelId == user.HotelId && i.ReservationRoomId == reservationRoomId);
                var roomESItemsQuery = context.RoomExtraServiceItems.Where(resi => resi.HotelId == user.HotelId && resi.ReservationRoomId == reservationRoomId);
                var paymentQuery = context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == reservationRoomId);
                var currenciesQuery = context.Money.Where(mon => mon.HotelId == user.HotelId);

                var sharerQuery = context.ReservationTravellers.Where(rt => rt.ReservationRoomId == reservation.room.ReservationRoomId);
                var countriesQuery = context.Countries.Where(c => c.CountryId == c.CountryId);
                var roomRemarksQuery = context.RoomRemarks.Where(rrm => rrm.HotelId == user.HotelId && rrm.ReservationRoomId == reservationRoomId);
                var roomBreakfastQuery = context.RoomBreakfast.Where(rb => rb.HotelId == user.HotelId && rb.ReservationRoomId == reservationRoomId);
                var marketQuery = context.Market.Where(mar => mar.HotelId == user.HotelId && mar.MarketId == reservation.reservation.MarketId);
                var sourceQuery = context.Source.Where(mar => mar.HotelId == user.HotelId && mar.SourceId == reservation.reservation.SourceId);
                var companyQuery = context.Company.Where(mar => mar.HotelId == user.HotelId && mar.CompanyId == reservation.reservation.CompanyId);
                var ChangeReservationStatusQuery = context.ChangeReservationStatus.Where(m => m.ReservationRoomId == reservationRoomId && m.ActionCode == "PRE_CHECKOUT");
                //
                var results3 = context.ExecuteQuery(pastCheckOutQuery, roomInfoQuery, roomTypeInfoQuery, planInfoQuery,
                                        roomESQuery,roomESItemsQuery, paymentQuery, currenciesQuery, sharerQuery,
                                        countriesQuery, roomRemarksQuery, roomBreakfastQuery, marketQuery, sourceQuery,
                                        companyQuery, ChangeReservationStatusQuery
                                        );

                
                var pastCheckOut = results3.GetResult<PastCheckOut>().FirstOrDefault();
                roomInfo = results3.GetResult<Rooms>().FirstOrDefault();
                var roomTypeInfo = results3.GetResult<RoomTypes>().FirstOrDefault();
                planInfo = results3.GetResult<RoomPrices>().FirstOrDefault();
                var roomExtraServices = results3.GetResult<RoomExtraServices>().ToList();
                var roomExtraServiceItems = results3.GetResult<RoomExtraServiceItems>().ToList();
                var payments = results3.GetResult<Payments>().ToList();
                var currenciesTmp = results3.GetResult<Money>().ToList();
                var sharer = results3.GetResult<ReservationTravellers>().ToList();
                var countries = results3.GetResult<Countries>().ToList();
                var roomRemarks = results3.GetResult<RoomRemarks>().ToList();
                var roomBreakfast = results3.GetResult<RoomBreakfast>().ToList();
                var market = results3.GetResult<Market>().FirstOrDefault();
                var source = results3.GetResult<Source>().FirstOrDefault();
                var company = results3.GetResult<Company>().FirstOrDefault();
                var ChangeReservationStatus = results3.GetResult<ChangeReservationStatus>().ToList();
                
                var paymentMethodsTmp = paymentMethods;
                //
                //var pastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == reservationRoomId).FirstOrDefault();
                if (pastCheckOut != null)
                {
                    applyPastCheckOut = true;
                    pastCheckOutReasonTemp = pastCheckOut.PastCheckOutReason;
                }
                var pastCheckOutReason = pastCheckOutReasonTemp;
                
                //var roomInfo = new Rooms();
                //if (reservation.room.RoomId != null)
                //{
                //    roomInfo = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == reservation.room.RoomId).FirstOrDefault();
                //}

                //var roomTypeInfo = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.RoomTypeId == reservation.room.RoomTypeId).FirstOrDefault();

                //var planInfo = new RoomPrices();
                //if (reservation.room.RoomPriceId != null)
                //{
                //    planInfo = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId && rp.RoomPriceId == reservation.room.RoomPriceId).FirstOrDefault();
                //}
                //var roomExtraServices = context.RoomExtraServices.Where(i => i.HotelId == user.HotelId && i.ReservationRoomId == reservationRoomId).ToList();
                //var roomExtraServiceInfo = new List<RoomExtraServiceCreatedUserInfo>();
                //foreach (var roomES in roomExtraServices)
                //{
                //    RoomExtraServiceCreatedUserInfo infoTemp = new RoomExtraServiceCreatedUserInfo();
                //    infoTemp.RoomExtraServiceId = roomES.RoomExtraServiceId;
                //    infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == roomES.CreatedUserId).FirstOrDefault().UserName;
                //    if (roomES.IsDeleted)
                //    {
                //        infoTemp.UserNameDeleted = context.AspNetUsers.Where(usr => usr.Id == roomES.DeletedBy).FirstOrDefault().UserName;
                //    }
                //    roomExtraServiceInfo.Add(infoTemp);
                //}
                ////var roomExtraServiceItems = context.RoomExtraServiceItems.Where(resi => resi.HotelId == user.HotelId && resi.ReservationRoomId == reservationRoomId).ToList();
                //var roomExtraServiceItemInfo = new List<RoomExtraServiceItemCreatedUserInfo>();
                //foreach (var roomESI in roomExtraServiceItems)
                //{
                //    if (roomESI.IsDeleted)
                //    {
                //        RoomExtraServiceItemCreatedUserInfo infoTemp = new RoomExtraServiceItemCreatedUserInfo();
                //        infoTemp.RoomExtraServiceItemId = roomESI.RoomExtraServiceItemId;
                //        infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == roomESI.DeletedBy).FirstOrDefault().UserName;
                //        roomExtraServiceItemInfo.Add(infoTemp);
                //    }
                //}
                //var extraServices = context.ExtraServiceTypes.Where(r => r.HotelId == user.HotelId).ToList();
                //var esCat = context.ExtraServiceCategories.Where(c => c.HotelId == user.HotelId && !c.IsHidden).ToList();
                //var extraServiceItems = context.ExtraServiceItems.Where(r => r.HotelId == user.HotelId && !r.IsHidden && esCat.Contains(r.ExtraServiceCategories)).ToList();
                var extraServices = ExtraService.ExtraServiceTypes.ToList();
                var esCat = ExtraService.ExtraServiceCategories.ToList();
                var extraServiceItems = ExtraService.ExtraServiceItems.ToList();
                //var payments = context.Payments.Where(p => p.HotelId == user.HotelId && p.ReservationRoomId == reservationRoomId).ToList();
                //var paymentInfo = new List<PaymentInfo>();
                //foreach (var payment in payments)
                //{
                //    PaymentInfo infoTemp = new PaymentInfo();
                //    infoTemp.PaymentId = payment.PaymentId;
                //    infoTemp.UserName = context.AspNetUsers.Where(usr => usr.Id == payment.CreatedUserId).FirstOrDefault().UserName;
                //    paymentInfo.Add(infoTemp);
                //}

                //var currenciesTmp = context.Money.Where(mon => mon.HotelId == user.HotelId).ToList();
                var currenciesISOTmp = new List<Currencies>();
                foreach (var currency in currenciesTmp)
                {
                    var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                    if (iso != null)
                    {
                        currenciesISOTmp.Add(iso);
                    }
                }
                var defaultCurrencyTmp = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
                //var paymentMethodsTmp = context.PaymentMethods.Where(pay => pay.PaymentMethodId == pay.PaymentMethodId).ToList();
                //var sharer = context.ReservationTravellers.Where(rt => rt.ReservationRoomId == reservation.room.ReservationRoomId).ToList();
                List<SharerViewModel> sharerList = new List<SharerViewModel>();
                foreach (var sha in sharer)
                {
                    SharerViewModel temp = new SharerViewModel();
                    temp.customer = context.Travellers.Where(s => s.HotelId == user.HotelId && s.TravellerId == sha.TravellerId).FirstOrDefault();
                    if (temp.customer.CountryId == null)
                    {
                        var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                        temp.customer.CountryId = country.CountryId;
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                    }
                    temp.reservationRoomId = reservationRoomId.Value;

                    ReservationTravellerExtraInformation travellerExtra = context.ReservationTravellerExtraInformation.Where(ex => ex.HotelId == user.HotelId && ex.ReservationTravellerId == sha.ReservationTravellerId).FirstOrDefault();
                    if (travellerExtra == null)
                    {
                        travellerExtra = new ReservationTravellerExtraInformation();
                        travellerExtra.HotelId = user.HotelId;
                        travellerExtra.ReservationTravellerId = sha.ReservationTravellerId;
                        travellerExtra.IsChild = false;
                        context.ReservationTravellerExtraInformation.InsertOnSubmit(travellerExtra);
                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);
                    }
                    temp.travellerExtraInfo = travellerExtra;
                    sharerList.Add(temp);
                }
                //List<Countries> countries = context.Countries.Where(c => c.CountryId == c.CountryId).ToList();

                //List<RoomRemarks> roomRemarks = context.RoomRemarks.Where(rrm => rrm.HotelId == user.HotelId && rrm.ReservationRoomId == reservationRoomId).ToList();
                //List<RoomBreakfast> roomBreakfast = context.RoomBreakfast.Where(rb => rb.HotelId == user.HotelId && rb.ReservationRoomId == reservationRoomId).ToList();

                //var market = context.Market.FirstOrDefault(mar => mar.HotelId == user.HotelId && mar.MarketId == reservation.reservation.MarketId);
                //var source =
                //    context.Source.FirstOrDefault(
                //        mar => mar.HotelId == user.HotelId && mar.SourceId == reservation.reservation.SourceId);
                //var company =
                //    context.Company.FirstOrDefault(
                //        mar => mar.HotelId == user.HotelId && mar.CompanyId == reservation.reservation.CompanyId);
                //check pre checkout 
                bool IsPreCheckOut = false;
                //var ChangeReservationStatus = context.ChangeReservationStatus.Where(m => m.ReservationRoomId == reservationRoomId && m.ActionCode == "PRE_CHECKOUT").ToList();
                if (ChangeReservationStatus.Count() > 0)
                {
                    IsPreCheckOut = true;
                }
                if (reservation.room.RoomId == null)
                {
                    roomInfo = new Rooms();
                }
                if (reservation.room.RoomPriceId == null)
                {
                    planInfo = new RoomPrices();
                }
                reservationInfo = new
                {
                    applyPastCheckOut = applyPastCheckOut,
                    pastCheckOutReason = pastCheckOutReason,
                    room = reservation.room,
                    CMBookingId = reservation.reservation.CMBookingId,
                    CMChannelRef=reservation.reservation.CMChannelRef,
                    reservationNumber = reservation.reservationNumber,
                    planInfo = planInfo,
                    roomInfo = roomInfo,
                    roomTypeInfo = roomTypeInfo,
                    customer = reservation.customer,
                    sharerList = sharerList,
                    roomExtraServices = roomExtraServices,
                    roomExtraServiceItems = roomExtraServiceItems,
                    //roomExtraServiceInfo = roomExtraServiceInfo,
                    //PaymentInfo = paymentInfo,
                    //roomExtraServiceItemInfo = roomExtraServiceItemInfo,
                    extraServices = extraServices,
                    extraServiceItems = extraServiceItems,
                    Payments = payments,
                    
                    currencies = currencies,
                    currenciesISO = currenciesISO,
                    defaultCurrency = new
                    {
                        MoneyId = defaultCurrencyTmp.MoneyId,
                        MoneyName = defaultCurrencyTmp.MoneyName
                    },
                    paymentMethods = paymentMethodsTmp,
                    countries = countries,
                    roomRemarks = roomRemarks,
                    roomBreakfast = roomBreakfast,
                    company = company,
                    source = source,
                    market = market,
                    roomCharges = reservation.roomCharges,
                    IsPreCheckOut = IsPreCheckOut,
                    ListUser
                };
                
                #region CalculateRoomPrice
                if (reservation.room.BookingStatus == "CHECKIN"  || reservation.room.BookingStatus== "BOOKED")
                {
                    int roomIdTemp = 0;
                    if (reservation.room.RoomId != null)
                    {
                        roomIdTemp = reservation.room.RoomId.Value;
                    }
                    RoomPrice = new CalculateRoomPrice()
                    {
                        roomId = roomIdTemp,
                        arrivalDate = reservation.room.ArrivalDate.Value,
                        departureDate = DateTime.UtcNow,
                        adults = reservation.room.Adults,
                        children = reservation.room.Child,
                        RoomPriceId = reservation.room.RoomPriceId,
                        FOC = reservation.room.Foc,
                        DiscountPercentage = (float)reservation.room.DiscountPercentage,
                        DiscountFlat = reservation.room.DiscountFlat,
                        Price = reservation.room.Price,
                        reservationRoomId = reservation.room.ReservationRoomId,
                        roomTypeId = (int)reservation.room.RoomTypeId
                    };
                    if (applyPastCheckOut)
                    {
                        RoomPrice.departureDate = reservation.room.DepartureDate.Value;
                    }
                    if (reservation.room.BookingStatus == "BOOKED" || reservation.room.BookingStatus == "NOSHOW")
                    {
                        RoomPrice.departureDate = reservation.room.DepartureDate.Value;
                    }
                    var CalculateRoomPriceTmp = await RoomPriceUtilities.CalculateRoomPrice(RoomPrice);
                    CalculateRoomPrice = CalculateRoomPriceTmp;
                }

                #endregion
                #endregion
            }
            //var endTime1 = DateTime.Now;
            var ReservationRoom = new
            {
                RoomInvoice,
                RoomStatus= retval,
                AllCustomer= Travellers,
                ExtraService,
                reservationInfo,
                CalculateRoomPrice,
                RoomPrice
            };
            memCache.AddByHotelId(user.HotelId, "ROOMRESERVATION_" + reservationRoomId, ReservationRoom, DateTimeOffset.UtcNow.AddMinutes(5));
            return Ok(ReservationRoom);
        }
        #endregion
        #region Guest Database
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddGuestDatabase")]
        public async Task<IHttpActionResult> AddGuestDatabase(Travellers model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            model.CreatedDate = DateTime.UtcNow;
            model.CreatedUserId = user.UserId;
            model.HotelId = user.HotelId;

            context.Travellers.InsertOnSubmit(model);
            context.SubmitChanges();
            Common.Elastic.IndexLastAudit(context);
            return Ok(model);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditGuestDatabase")]
        public async Task<IHttpActionResult> EditGuestDatabase(Travellers model)
        {
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault();
            Travellers oldSharer = context.Travellers.Where(sh => sh.TravellerId == model.TravellerId && sh.HotelId == user.HotelId).FirstOrDefault();
            if (oldSharer != null)
            {
                oldSharer.Fullname = model.Fullname;
                oldSharer.Mobile = model.Mobile;
                oldSharer.Email = model.Email;
                oldSharer.IdentityNumber = model.IdentityNumber;
                oldSharer.Birthday = model.Birthday.HasValue ? model.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                oldSharer.Address = model.Address;
                oldSharer.Gender = model.Gender;
                oldSharer.CountryId = model.CountryId;
                oldSharer.Note = model.Note;
                oldSharer.ModifiedDate = DateTime.UtcNow;
                oldSharer.ModifiedUserId = user.UserId;
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                return Ok();
            }
            else
            {
                return BadRequest("ERROR");
            }
        }
        [HttpPost]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DeleteGuestDatabase")]
        public async Task<IHttpActionResult> DeleteGuestDatabase(int TravellerId, bool IsDelete)
        {
            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault();
            Travellers oldSharer = context.Travellers.Where(sh => sh.TravellerId == TravellerId).FirstOrDefault();
            if (oldSharer != null)
            {
                oldSharer.IsDeleted = IsDelete;
                if (IsDelete)
                {
                    oldSharer.DeletedDate = DateTime.UtcNow;
                    oldSharer.DeletedUserId = user.UserId;
                }
                else
                {
                    oldSharer.ModifiedDate = DateTime.UtcNow;
                    oldSharer.ModifiedUserId = user.UserId;
                }
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                return Ok();
            }
            else
            {
                return BadRequest("ERROR");
            }
        }
        #endregion
        #region Search Guest
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchCustomer")]
        public async Task<IHttpActionResult> SearchCustomer(SearchCustomerModel model)
        {
            int takeRecord = 10;
            var startTime = DateTime.Now;
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var travellers = context.Travellers.Where(t => t.HotelId == user.HotelId && t.Fullname.ToLower().Contains(model.CustomerName.ToLower()))
                .Skip(model.SkipRecord)
                .Take(takeRecord).Select(s => new
                {
                    s.TravellerId,
                    s.Fullname,
                    s.IdentityNumber,
                    s.Countries.CountryName,
                    s.CountryId,
                    s.Mobile,
                    s.Address,
                    s.Gender,
                    s.Birthday,
                    s.Email,
                    s.Note
                }).ToList().OrderBy(s => s.TravellerId);
            var totalTraveller = context.Travellers.Where(t => t.HotelId == user.HotelId && t.Fullname.Contains(model.CustomerName)).Count();
            var endTime = DateTime.Now;
            return Ok(new
            {
                Travellers = travellers,
                TotalRecord = totalTraveller,
                SkipRecord = model.SkipRecord,
                ExecutionTime = (endTime - startTime).TotalMilliseconds
            });
        }
        public class SearchCustomerModel
        {
            public string CustomerName { set; get; }
            public int SkipRecord { set; get; }
        }
        #endregion

    }
}